--- layout: archive title: Zulip Chat Archive permalink: /stream/113489-new-members/topic/noob.20question(s).html ---

Stream: new members

Topic: noob question(s)


{% raw %}

view this post on Zulip Wojciech Nawrocki (Nov 20 2018 at 00:46):

What's the command to make Lean automatically derive decidable_eq for some custom inductive type?

view this post on Zulip Chris Hughes (Nov 20 2018 at 00:47):

@[derive decidable_eq]

view this post on Zulip Wojciech Nawrocki (Nov 20 2018 at 00:47):

ah I should've thought of that, thanks! :)

view this post on Zulip Wojciech Nawrocki (Nov 20 2018 at 03:18):

Hm, when I add

open classical
local attribute [instance] prop_decidable

to a file, definitions below it which used to pass now fail with:

equation compiler failed to generate bytecode for 'subst._main'
nested exception message:
code generation failed, VM does not have code for 'classical.choice'

Why might this be?

Is it basically because classical makes things uncomputable? If so, maybe Lean should detect that classical is not used in a particular case and still compile the definition?

view this post on Zulip Chris Hughes (Nov 20 2018 at 03:21):

Try [instance, priority 0]. Otherwise it uses classical decidability even when there's proper decidability.

view this post on Zulip Wojciech Nawrocki (Nov 20 2018 at 03:23):

Ah indeed, thanks Chris!

view this post on Zulip Kevin Buzzard (Nov 20 2018 at 08:22):

This trips lots of people up! I wonder where people are learning this trick? Not putting priority 0 can trip you up later in quite a confusing way

view this post on Zulip Patrick Massot (Nov 20 2018 at 08:23):

@Jeremy Avigad needs to fix the very bottom of https://leanprover.github.io/theorem_proving_in_lean/axioms_and_computation.html

view this post on Zulip Johan Commelin (Nov 20 2018 at 08:23):

I think Lean shows an error message when it can't find an instance for decidable, and that error message does not include setting the priority. It would be very helpful if it did.

view this post on Zulip Patrick Massot (Nov 20 2018 at 08:23):

and https://leanprover.github.io/theorem_proving_in_lean/type_classes.html

view this post on Zulip Jeremy Avigad (Nov 20 2018 at 15:03):

I'm on it -- I'll do it tomorrow.

view this post on Zulip Patrick Massot (Nov 20 2018 at 16:08):

Thanks!

view this post on Zulip Kenny Lau (Nov 20 2018 at 16:09):

how about not using classical.dec

view this post on Zulip Reid Barton (Nov 20 2018 at 16:10):

Let's just agree to not not use it

view this post on Zulip Kenny Lau (Nov 20 2018 at 16:11):

that doesn't mean we use it :P

view this post on Zulip Patrick Massot (Nov 20 2018 at 16:11):

You may have missed Reid's point

view this post on Zulip Reid Barton (Nov 20 2018 at 16:11):

It doesn't mean you use it

view this post on Zulip Wojciech Nawrocki (Nov 20 2018 at 22:59):

Is it possible to make Lean display the values of constant variables in the tactic state? E.g. if i have lst: list nat which is also empty, it would be nice to see that it's empty.

view this post on Zulip Kenny Lau (Nov 20 2018 at 23:01):

either this doesn't make sense, or subst lst

view this post on Zulip Wojciech Nawrocki (Nov 20 2018 at 23:04):

Hm I should elaborate, maybe I'm misunderstanding how induction works. Say I have a hypothesis h: InductiveFoo list.nil, where InductiveFoo: list nat -> Prop. So then running induction h creates cases for all the constructors of InductiveFoo, which take the list as an input, say lst. But the lst is empty, so it'd be nice to see that in the state.

view this post on Zulip Kenny Lau (Nov 20 2018 at 23:06):

you can't because it's forgotten

view this post on Zulip Kenny Lau (Nov 20 2018 at 23:06):

you might want to generalize_hyp

view this post on Zulip Wojciech Nawrocki (Nov 20 2018 at 23:16):

Thanks!

view this post on Zulip Wojciech Nawrocki (Nov 21 2018 at 15:03):

Perhaps it would be useful to have a reference sheet for translating from Coq to Lean tactics?

view this post on Zulip Mario Carneiro (Nov 21 2018 at 15:05):

I recall such a thing being made at one point. Maybe it's in mathlib docs?

view this post on Zulip Rob Lewis (Nov 21 2018 at 15:05):

https://github.com/jldodds/coq-lean-cheatsheet

view this post on Zulip Rob Lewis (Nov 21 2018 at 15:05):

Note the date though, it'll need updating.

view this post on Zulip Wojciech Nawrocki (Nov 21 2018 at 15:06):

Oh, nice!

view this post on Zulip Wojciech Nawrocki (Nov 21 2018 at 16:06):

Is there a general tactic for showing false by "this term could not have been constructed"? E.g.

inductive Foo: Prop  Prop  Prop
| FooT: Foo true true
| FooF: Foo false false

-- This term could not have been constructed
lemma impossible (h: Foo true false)
  : false := by sorry

view this post on Zulip Mario Carneiro (Nov 21 2018 at 16:11):

cases

view this post on Zulip Mario Carneiro (Nov 21 2018 at 16:11):

also empty match

view this post on Zulip Mario Carneiro (Nov 21 2018 at 16:11):

lemma impossible : Foo true false → false.

view this post on Zulip Rob Lewis (Nov 21 2018 at 16:12):

You have to make Foo : bool -> bool -> Prop for that.

view this post on Zulip Wojciech Nawrocki (Nov 21 2018 at 16:13):

Yeah, for Prop -> Prop -> Prop both of these fail, but that wasn't actually my problem, so thanks!

view this post on Zulip Patrick Massot (Nov 21 2018 at 16:16):

It seems that variations on this topic comes up again and again. We should really find a way to document that

view this post on Zulip Wojciech Nawrocki (Nov 21 2018 at 20:17):

That would be nice :) I was also surprised to see that more often than not contradiction fails when cases h works. Description: The contradiction tactic attempts to find in the current local context an hypothesis that is equivalent to an empty inductive type (e.g. false). I thought a hypothesis that cannot be constructed is exactly that, but maybe I'm misunderstanding it?

view this post on Zulip Wojciech Nawrocki (Nov 22 2018 at 01:12):

Is it possible to reserve some notation for an inductive type and then use it while defining the type, like in Coq? I tried this, but the parser seems to fail:

reserve infix ``:50

inductive Typeof: list Tp  Tp  Prop
| Z:  (Γ: list Tp) A, Typeof (Γ.append [A]) A
| S_:  (Γ: list Tp) A B, Typeof Γ A  Typeof (Γ.append [B]) A

inductive Typeof: list Tp  Tp  Prop
| Z:  (Γ: list Tp) A, (Γ.append [A])  A -- fails
| S_:  (Γ: list Tp) A B, Γ  A  (Γ.append [B])  A

infix  := Typeof

view this post on Zulip Mario Carneiro (Nov 22 2018 at 03:00):

Yes! You can just put a notation line between the inductive header and the first constructor

inductive Typeof{Tp}: list Tp  Tp  Prop
infix ``:50 := Typeof
| Z:  (Γ: list Tp) A, (Γ.append [A])  A
| S_:  (Γ: list Tp) A B, Γ  A  (Γ.append [B])  A

view this post on Zulip Jeremy Avigad (Nov 23 2018 at 16:29):

@Patrick Massot I added a discussion of the priority 0 trick to Section 10.4 of TPIL (search on "priority 0"):
https://leanprover.github.io/theorem_proving_in_lean/type_classes.html#decidable-propositions
I also added a back reference in Section 11:
https://leanprover.github.io/theorem_proving_in_lean/axioms_and_computation.html#the-law-of-the-excluded-middle

Finally, I fixed an old issue raised by @Joseph Corneli by changing all the examples in 6.4:
https://leanprover.github.io/theorem_proving_in_lean/interacting_with_lean.html#attributes
https://github.com/leanprover/theorem_proving_in_lean/issues/62

Teaching my class next semester will give me a chance to review and expand TPIL. I am planning to add one more chapter on some of the fine points of dependent type theory, e.g. explaining how to work with equality and dependent types (the dark side of type theory), and explaining how Lean manages recursion on arbitrary well-founded relations. I'll also try to write a less ambitious but up-to-date version of Programming in Lean. But I am counting on the mathlib crew to continue documenting mathlib and all the new tactics, and to provide useful guidance on using the library and proving theorems.

view this post on Zulip Kevin Buzzard (Nov 23 2018 at 16:33):

I have not been using Lean seriously since term started; there are three weeks to go before it finishes. After that I fully intend to go back to the perfectoid project. But when I don't understand something, my instinct is to write docs about it, because if I work something out and don't write down what I learnt then I realise a month later that I've forgotten it all again!

view this post on Zulip Patrick Massot (Nov 23 2018 at 20:02):

Thank you very much Jeremy! Your documentation work is really crucial.

view this post on Zulip Patrick Massot (Nov 23 2018 at 21:06):

I'm now reading random pieces of TPIL, and I have a couple more suggestions about chapter 10:

#check (by apply_instance : has_add )
#reduce (infer_instance : has_add )

maybe find a better example for the second one since the answer is not super easy to read (every nice example coming to my mind are in mathlib...)

view this post on Zulip Patrick Massot (Nov 23 2018 at 21:09):

Oh, it seems apply_instance is never mentioned in TPIL :sad:

view this post on Zulip Patrick Massot (Nov 23 2018 at 21:10):

Another thing that would be very helpful, both because it can be puzzling and because it can be very helpful would be to discuss

def n : Type := 

example : has_add  := by apply_instance  -- ok
example : has_add n := by apply_instance  -- fails
example : has_add n := by unfold n ; apply_instance  -- ok

view this post on Zulip Jeremy Avigad (Nov 24 2018 at 13:23):

Thanks for the input. Yes, TPIL evolved over time, and the last major rewrite was early in the days of Lean 3, before there was a VSCode extension. I'll do a global search and try to make the text less emacs-centric.

I'll discuss apply_instance and infer_instance. I am thinking of using these examples:

/- example 1: using apply_instance -/

def foo : has_add nat := by apply_instance
def bar : inhabited (nat  nat) := by apply_instance

/- example 2: using infer_instance -/

def baz : has_add nat := infer_instance
def bla : inhabited (nat  nat) := infer_instance

/- example 3: seeing them -/

#print foo    -- nat.has_add
#reduce foo   -- (unreadable)

#print bar    -- pi.inhabited ℕ
#reduce bar   -- {default := λ (a : ℕ), 0}

#print baz    -- infer_instance
#reduce baz   -- (same as for #reduce foo)

#print bla    -- infer_instance
#reduce bla   -- {default := λ (a : ℕ), 0}

/- example 4: tricks to be more concise -/

#check (by apply_instance : inhabited )
#print nat.inhabited

#reduce (infer_instance : inhabited )

/- examples 5: core Lean can't find an instance for inhabited set -/

-- fails
-- example {α : Type*} : inhabited (set α) := by apply_instance

/- example 6: supplying one manually -/

def inhabited.set (α : Type*) : inhabited (set α) := 
#print inhabited.set     -- λ {α : Type u}, {default := ∅}
#reduce inhabited.set   -- {default := λ (a : ℕ), false}

/- example 7: unfolding a definition so Lean can find it -/

def inhabited.set (α : Type*) : inhabited (set α) :=
by unfold set; apply_instance
#print inhabited.set     -- λ (α : Type u), eq.mpr _ (pi.inhabited α)
#reduce inhabited.set   -- {default := λ (a : ℕ), true}

/- example 8: using dunfold instead -/

def inhabited.set (α : Type*) : inhabited (set α) :=
by dunfold set; apply_instance
#print inhabited.set     -- λ (α : Type u), id (pi.inhabited α)
#reduce inhabited.set   -- {default := λ (a : ℕ), true}

view this post on Zulip Patrick Massot (Dec 11 2018 at 09:17):

Yes! You can just put a notation line between the inductive header and the first constructor

inductive Typeof{Tp}: list Tp  Tp  Prop
infix ``:50 := Typeof
| Z:  (Γ: list Tp) A, (Γ.append [A])  A
| S_:  (Γ: list Tp) A B, Γ  A  (Γ.append [B])  A

Is there something similar for dependant structure? If one field of my structure is a binary operator, can I define an infix notation usable in the remaining fields declaration?

view this post on Zulip Kevin Buzzard (Dec 11 2018 at 09:18):

I usually make the structure extend the notation typeclass in this situation.

view this post on Zulip Kevin Buzzard (Dec 11 2018 at 09:19):

In fact I have been known to make new notation typeclasses called things like group_notation extending has_mul, has_one and has_inv, and then extending these too so I get a bunch of notation at once.

view this post on Zulip Patrick Massot (Dec 11 2018 at 09:21):

Thanks Kevin. I know all this, but I'm still interested in an answer to my question.

view this post on Zulip Kevin Buzzard (Dec 11 2018 at 09:21):

Yes I understand. For example if the notation is not in the standard notation list then it would be nicer to add it directly in the definition of the structure.

view this post on Zulip Rob Lewis (Dec 11 2018 at 12:05):

You can define notation in structures that's used in the remaining fields. But I think it's just local to the structure declaration.

structure patrick :=
(α : Type)
(f : α  α  α)
(infix `^^^`:50 := f)
(h :  a : α, a ^^^ a = a)

#check patrick.h

view this post on Zulip Patrick Massot (Dec 11 2018 at 13:29):

Thanks!

view this post on Zulip Jeremy Avigad (Jan 03 2019 at 18:49):

I just crossed this item off my to do list. apply_inference and such are now discussed here: https://leanprover.github.io/theorem_proving_in_lean/type_classes.html#managing-type-class-inference. And VS Code is now mentioned whenever Emacs is, with VS Code first.

view this post on Zulip Patrick Massot (Jan 03 2019 at 18:54):

If you add this to your file in Emacs mode and use C-c C-x to run an independent Lean process on your file, the output buffer will show a trace every time the type class resolution procedure is subsequently triggered.

This paragraph (in the section your referred to) is still Emacs centric

view this post on Zulip Jeremy Avigad (Jan 03 2019 at 19:20):

Yes, that is the only one, because I don't know how to start an independent Lean process from within VS Code. I guess I'll remind people that they can run Lean from the VS Code terminal.

view this post on Zulip Patrick Massot (Jan 03 2019 at 19:20):

Why would you do that?

view this post on Zulip Patrick Massot (Jan 03 2019 at 19:20):

The trace is printed in the info view

view this post on Zulip Jeremy Avigad (Jan 03 2019 at 19:23):

Oh! I forgot. Good point. I'll fix that.

view this post on Zulip Patrick Massot (Jan 03 2019 at 19:24):

Great!

view this post on Zulip Jeremy Avigad (Jan 03 2019 at 19:34):

Fixed. Thanks for catching it.
https://leanprover.github.io/theorem_proving_in_lean/type_classes.html#managing-type-class-inference

view this post on Zulip Wojciech Nawrocki (Jan 16 2019 at 12:50):

Hello! Is there anything special I need to do to make Lean recognise my instance : has_zero Foo as being equivalent to 0? I got this state while trying to use rw [this]:

rewrite tactic failed, did not find instance of the pattern in the target expression
  0 + π₂
state:
3 goals
π₂ : mult,
this : 0 + π₂ = π₂
 mult.Zero + π₂ = π₂ + mult.Zero

even though I have

instance : has_zero mult :=
  mult.Zero

above

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 12:55):

rewrites don't recognise definitional equality, only syntactic equality.

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 12:55):

So you could try "show 0 + pi2 = _" before the rewrite

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 12:56):

or "change mult.Zero + _ = _ at this". Maybe it will work after one of these changes. But not after both ;-)

view this post on Zulip Reid Barton (Jan 16 2019 at 12:56):

convert this should also work

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 12:57):

but this isn't the goal

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 12:57):

Oh!

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 12:58):

This convert trick works when the thing you're rewriting is precisely one side of the equality I guess.

view this post on Zulip Reid Barton (Jan 16 2019 at 12:58):

or erw this would also work but it's not as nice

view this post on Zulip Reid Barton (Jan 16 2019 at 13:01):

In fact you can use a' = b' to prove a = b with neither side matching definitionally (you'll get two new goals a = a' and b = b'), but then you run the risk that the new goals are not actually true :smile:

view this post on Zulip Wojciech Nawrocki (Jan 16 2019 at 13:13):

Ah, I see, thanks! And related, I'm proving that an object with three elements and custom add/mult tables is a semiring, how ugly is it to do all my proofs like this?

  lemma add_assoc (π₁ π₂ π₃: mult)
    : π₁ + π₂ + π₃ = π₁ + (π₂ + π₃) := by { cases π₁; cases π₂; cases π₃; refl }

view this post on Zulip Mario Carneiro (Jan 16 2019 at 13:17):

it will work, although there are simpler proofs where you ony case on one of them, I think

view this post on Zulip Wojciech Nawrocki (Jan 16 2019 at 13:20):

Hm, I found that without expanding every case, I had to do a bit more work by using other lemmas and so on. The definition of add is:

inductive mult: Type
| Zero: mult
| One: mult
| Omega: mult

instance : has_zero mult :=
  mult.Zero

instance : has_one mult :=
  mult.One

notation `ω` := mult.Omega

def add: mult  mult  mult
| 0 π := π
| π 0 := π
| 1 1 := ω
| ω _ := ω
| _ ω := ω

instance : has_add mult :=
  add

view this post on Zulip Mario Carneiro (Jan 16 2019 at 13:22):

right

view this post on Zulip Mario Carneiro (Jan 16 2019 at 13:24):

you should have lemmas like x + ω = ω as simp lemmas which should simplify most of the cases

view this post on Zulip Mario Carneiro (Jan 16 2019 at 13:25):

or you could just split into 27 cases if you want

view this post on Zulip Wojciech Nawrocki (Jan 16 2019 at 13:26):

Ah ok, i'll try it with simp as well, thanks!

view this post on Zulip Johan Commelin (Jan 16 2019 at 13:55):

Scott Morrison's case-bashing tactic would probably be useful here. But I don't know where that tactic lives at the moment...

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:01):

if you want to do a case bashing proof, another approach is to prove fintype mult and decidable_eq mult (you can derive this), and then you can just revert everything and use dec_trivial

view this post on Zulip Johan Commelin (Jan 16 2019 at 14:02):

Should even be reasonably fast, I guess.

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:02):

as long as you don't have too many variables; it is still 27 cases

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 14:18):

Kind of a stupid question, but when I'm using other computer algebra systems I would expect checking a million cases to be very quick. Mario's comments suggest that 27 is rather large for Lean. What is happening here?

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:37):

There is a large overhead of the expression that is generated, elaboration for it, and typechecking

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:38):

I don't think 27 is that large in this context, I guess it's probably less than a second to check

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:38):

I just think it's better to have more "human" proofs with fewer cases

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 14:38):

This is what I don't understand. We have to check that 27 things of the form add a (add b c) = add (add a b) c hold and in each case this is by refl.

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 14:39):

How long does it take Lean to prove (0 + 1) + 1 = 0 + (1 + 1) in this type?

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:40):

there is also all the intermediate steps, the generation of motives, lots of abstraction and substitution going on, and large terms being built up behind the scenes before you even attack those 27 cases

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 14:40):

So the bottleneck is elsewhere?

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:41):

I have heard it repeatedly asserted that the kernel is not a bottleneck

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 14:41):

Again the idea of a "large" term is confusing to me. In python I could happily manipulate a list with 1000 elements.

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:41):

this term has way more than 1000 subterms

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 14:41):

One of my kids has been learning about algorithms over the last few months and I realise now that I am far more aware of these things than I used to be.

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:42):

all in all it makes lean just look a lot slower to do "simple" things

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:42):

because there is a lot of bookkeeping in the background

view this post on Zulip Mario Carneiro (Jan 16 2019 at 14:44):

I would like to figure out ways to minimize the overhead, but that runs close to work on the lean compiler

view this post on Zulip Kevin Buzzard (Jan 16 2019 at 15:28):

this term has way more than 1000 subterms

In the same way that a set with 10 elements has more than 1000 subsets, or in a more serious "we really need to work with way more than 1000 things" way?

view this post on Zulip Mario Carneiro (Jan 16 2019 at 15:50):

in the more serious way. (It's tricky to count the "size" of an expression but number of subterms is a good proxy)

view this post on Zulip Mario Carneiro (Jan 16 2019 at 15:51):

there is no exponential growth because subterms can't overlap, they are either disjoint or in a containment relationship

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 00:04):

Is it possible to define a custom synthesis strategy for an implicit argument? I would like to define a function which extracts concrete values from concrete lists, like so:

def get':  (l: list ) (n: ) {h: n < l.length}, 
| (x::xs) 0 _ := x
| (x::xs) (n+1) h := @get' xs n (nat.lt_of_succ_lt_succ h)
| [] n h := by { exfalso, simp at h, exact (nat.not_lt_zero n)

and for concrete args, h is always derivable with a custom tactic. I'd like Lean to use that tactic to synthesise it.
OR am I doing this completely wrong and there is a much simpler way?

view this post on Zulip Chris Hughes (Jan 18 2019 at 00:07):

unification hints! I don't know much about them though.

view this post on Zulip Mario Carneiro (Jan 18 2019 at 00:51):

This function is list.nth_le btw

view this post on Zulip Mario Carneiro (Jan 18 2019 at 00:53):

you can synthesize the argument using typeclasses, but exact_dec_trivial is another easy way to do it

view this post on Zulip Mario Carneiro (Jan 18 2019 at 00:54):

def get' (l : list ) (n : ) (h : n < l.length . exact_dec_trivial) :  := l.nth_le n h

example : get' [1, 2, 3] 1 = 2 := rfl

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 01:07):

Ah indeed, thanks Mario! Can I use something like this in a Pi-type (to make the equation compiler work)? The foo . tactic syntax doesn't seem to work:

def debrujin_of_nat: Π {Γ: Env} (n: ) (h: n < Γ.length . tactic.exact_dec_trivial), (Γ  Γ.nth_le n h) -- ill-formed declaration

view this post on Zulip Mario Carneiro (Jan 18 2019 at 01:14):

If you can put it left of the colon, the dot notation should work. But if you can't write it that way, it's sugar for auto_param:

def get' : Π (l : list ) (n : ), auto_param (n < l.length) ``exact_dec_trivial   := list.nth_le

example : get' [1, 2, 3] 1 = 2 := rfl

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 01:19):

Can I have a _named_ auto_param :sweat_smile:? I need to use the hypothesis in the type signature itself, more specifically in the return type.

view this post on Zulip Mario Carneiro (Jan 18 2019 at 01:21):

sure, just use a pi instead of an arrow

view this post on Zulip Mario Carneiro (Jan 18 2019 at 01:21):

auto_param T n is defeq to T so it doesn't cause any problems

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 01:27):

Oh, I was sure I'd tried that but apparently not, thanks! Doesn't seem to work under #eval unfortunately:

don't know how to synthesize placeholder
context:
 auto_param (0 < list.length [Tp.Nat]) (name.mk_string "exact_dec_trivial" (name.mk_string "tactic" name.anonymous))

view this post on Zulip Mario Carneiro (Jan 18 2019 at 01:29):

what did you write?

view this post on Zulip Mario Carneiro (Jan 18 2019 at 01:30):

it's not really related to the context you write it in, but rather the expected type during elaboration

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 01:35):

Apologies for the length, but this is the full context:

import tactic.find
import tactic.interactive
import tactic
import tactic.auto_cases
import tactic.tidy

@[derive decidable_eq]
inductive Tp
| Nat: Tp
| Bool: Tp
| Fn: Tp  Tp  Tp

local infixr `  `:50 := Tp.Fn

def Env := list Tp

inductive TypeIn: Env  Tp  Type
infix `  `:40 := TypeIn
| ZVar: Π {Γ T}, T::Γ  T
| SVar: Π {Γ T U}, Γ  T  U::Γ  T

local infix `  `:40 := TypeIn

open TypeIn

inductive Term: Env  Tp  Type
| Nat (n: ): Π {Γ}, Term Γ Tp.Nat -- in all environments, nat literals have type Nat
| Bool (b: bool): Π {Γ}, Term Γ Tp.Bool -- and booleans have type Bool
| Var: Π {Γ T}, Γ  T  Term Γ T -- A variable has type T given its de Brujin index
                                 -- is in the environment.
| Abs: Π {Γ T U}, Term (T::Γ) U  Term Γ (T  U)
| App: Π {Γ T U}, Term Γ (T  U)  Term Γ T  Term Γ U

open Term

def debrujin_of_nat: Π {Γ: Env} (n: ) {h: auto_param (n < Γ.length) ``tactic.exact_dec_trivial}, (Γ  Γ.nth_le n h)
| (T::Γ) 0 _ := ZVar
| (T::Γ) (n+1) h := SVar (@debrujin_of_nat Γ n (nat.lt_of_succ_lt_succ h))
| [] n h := by { exfalso, simp at h, exact (nat.not_lt_zero n) h }

local notation `#` n := Var (debrujin_of_nat n)

#eval (@App [] Tp.Nat Tp.Nat (@Abs [] Tp.Nat Tp.Nat (@Var [Tp.Nat] Tp.Nat (debrujin_of_nat 0))) (@Nat 3 []))

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 01:37):

Basically given a concrete list Tp and a concrete n, I'd like it to figure out that n is within bounds and include the result of lst.nth_le n _ in the return type.

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 01:41):

This does work: #eval (@App [] Tp.Nat Tp.Nat (@Abs [] Tp.Nat Tp.Nat (@Var [Tp.Nat] Tp.Nat (@debrujin_of_nat [Tp.Nat] 0 (by tactic.exact_dec_trivial)))) (@Nat 3 [])) (notice the explicit proof I put in)

view this post on Zulip Mario Carneiro (Jan 18 2019 at 02:06):

so what did you write?

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 02:07):

Well, the #eval at the bottom of that long snippet is what fails synthesis. The #eval with an explicit proof works

view this post on Zulip Mario Carneiro (Jan 18 2019 at 02:07):

aha, you made the arg implicit

view this post on Zulip Mario Carneiro (Jan 18 2019 at 02:07):

auto params should be explicit

view this post on Zulip Mario Carneiro (Jan 18 2019 at 02:07):

def debrujin_of_nat: Π {Γ: Env} (n: ℕ) (h: auto_param (n < Γ.length) ``tactic.exact_dec_trivial), (Γ ∋ Γ.nth_le n h)

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 02:09):

Oh thanks, now it does work, but still behaves as if it were implicit :thinking: is this currying at work, meaning I have to place auto_param last, s.t. given foo: nat -> auto_param blah -> nat, (foo n): nat (and foo n _ still fails)?

view this post on Zulip Wojciech Nawrocki (Jan 18 2019 at 23:39):

(unrelated to above)
I'm seeing a wierd error in an inductive type: invalid occurrence of recursive arg#3 of 'context.cons', the body of the functional type depends on it.. The type definition is below, and as far as I know it's a perfectly legit defn, so what's wrong?

inductive context: list   Type
| nil: context []
| cons {ns: list } (_: context ns) (n: ) (m: ): context (n::ns)

EDIT: swapping two arguments makes it compile, but why?

inductive context: list   Type
| nil: context []
| cons: Π {ns: list } (n: ) (_: context ns) (m: ), context (n::ns)

view this post on Zulip Mario Carneiro (Jan 18 2019 at 23:48):

I think Gabriel recently pointed out an example similar to this. You have a dependent pi (n) after a recursive arg (_ : context ns) and lean doesn't like this

view this post on Zulip Wojciech Nawrocki (Jan 19 2019 at 00:37):

Ah ok, maybe this could be fixed in Lean 4? :)

view this post on Zulip Wojciech Nawrocki (Jan 19 2019 at 01:51):

Do I need to do something special to make the semiring-ness of my custom type available to the ring tactic? I have a state like this:

π π' : mult,
π_1 : mult,
 π * π' * π_1 = π * (π' * π_1)

which is provable by exact mult.monoid.mul_assoc π π' π_1, but ring fails. I have instance : semiring mult shown a few lines above.

view this post on Zulip Mario Carneiro (Jan 19 2019 at 02:01):

you need to prove comm_semiring mult

view this post on Zulip Wojciech Nawrocki (Jan 21 2019 at 18:36):

Given def add (a b: foo): foo := blah, what's the difference between infix ++ := add and instance : has_add foo := ⟨add⟩? If i switch from the former to the latter and replace ++ with +, my proofs break at the simplification stage, namely addition seems to not be unfoldable anymore

view this post on Zulip Kevin Buzzard (Jan 21 2019 at 18:37):

They're very different in the sense that they're using different machinery to figure out what's going on.

view this post on Zulip Kevin Buzzard (Jan 21 2019 at 18:38):

I guess the infix trick is just syntax sugar, whereas the instance approach is using type class inference. Can you give an example of something which breaks?

view this post on Zulip Kevin Buzzard (Jan 21 2019 at 18:39):

I guess if you go via the instance approach then you have an extra layer of unfolding to do. + is has_add.add, which unfolds to your add.

view this post on Zulip Kevin Buzzard (Jan 21 2019 at 18:39):

Maybe that's the answer to your question. If you're trying to unfold things explicitly in the middle of a proof, maybe you have to insert some unfold has_add.add's

view this post on Zulip Kevin Buzzard (Jan 21 2019 at 18:40):

++ unfolds directly to your add, whereas + unfolds to has_add.add which unfolds to your add.

view this post on Zulip Kevin Buzzard (Jan 21 2019 at 18:42):

[NB I'm a bit of a CS noob, I don't know if "unfolds" is the right terminology for notation turning into its underlying definition]

view this post on Zulip Kevin Buzzard (Jan 21 2019 at 18:42):

[they might well be syntactically equal rather than just definitionally equal]

view this post on Zulip Wojciech Nawrocki (Jan 21 2019 at 19:29):

Ah indeed, unfolding twice does make it work - thanks!

view this post on Zulip Wojciech Nawrocki (Jan 22 2019 at 01:12):

Does there exist a general tactic for proving f a0 .. an = f b0 .. bn from a0 = b0 .. an = bn?

view this post on Zulip Mario Carneiro (Jan 22 2019 at 01:33):

congr

view this post on Zulip Wojciech Nawrocki (Jan 22 2019 at 01:36):

Hm, I tried congr but it seems to iterate the congruence, which gives me unprovable goals. Namely, I have a goal f (g x) = f (g y) and congr gives me x = y but I just want g x = g y. EDIT: congr' 1 works, thx!

view this post on Zulip Mario Carneiro (Jan 22 2019 at 02:37):

use congr' 1 and increase the number until you get a good result

view this post on Zulip Wojciech Nawrocki (Jan 22 2019 at 22:43):

The issue of has_add.add and its actual value not being definitionally equal makes a lot of my proofs quite ugly - I have to expand definitions first so that the expressions can simplify and then fold them back into the has_add.add version (or has_mul.mul, etc), because all the ring/module/whatever laws only work on those. For example:

  { /-
    case context.cons
    δ γ γ₁ : precontext,
    π₁ : mult,
    T₁ : tp,
    Γ₁ : context γ₁,
    ih₁ : ∀ {Γ₂ : context γ₁} {Ξ : matrix γ₁ δ}, vmul (Γ₁ + Γ₂) Ξ = vmul Γ₁ Ξ + vmul Γ₂ Ξ,
    Γ₂ : context (T₁ :: γ₁),
    Ξ : matrix (T₁ :: γ₁) δ
    ⊢ vmul (cons π₁ T₁ Γ₁ + Γ₂) Ξ = vmul (cons π₁ T₁ Γ₁) Ξ + vmul Γ₂ Ξ
    -/
    cases Γ₂ with _ π₂ _ Γ₂,
    -- unfold
    unfold vmul has_add.add context.add has_scalar.smul context.smul at *,
    simp *,
    -- fold back
    let a := vmul Γ₁ (λ (U : tp) (x : γ₁  U), Ξ U (SVar x)),
    let b := vmul Γ₂ (λ (U : tp) (x : γ₁  U), Ξ U (SVar x)),
    change
      (π₁ + π₂)  (Ξ T₁ ZVar) + (a + b)
      =
      (π₁(Ξ T₁ ZVar) + a) + (π₂(Ξ T₁ ZVar) + b),
    -- simplify using monoid laws
    simp [context.add_smul, context.add_assoc] },

is there some tactic or such that I could apply to do this automatically?

view this post on Zulip Mario Carneiro (Jan 22 2019 at 22:51):

This is what simp lemmas are for

view this post on Zulip Mario Carneiro (Jan 22 2019 at 22:53):

If you define add x (y :: z) := y :: add x z, for example, and then install add as a has_add instance, then you can prove x + (y :: z) = y :: (x + z) by rfl, and you should state this as a simp lemma

view this post on Zulip Mario Carneiro (Jan 22 2019 at 22:54):

You should not ever have to unfold has_add.add

view this post on Zulip Wojciech Nawrocki (Jan 22 2019 at 22:56):

Hm okay, so basically I need to "lift" the behaviour of my functions from the custom definition to one using has_op.op? I'll try

view this post on Zulip Wojciech Nawrocki (Jan 22 2019 at 23:09):

Is it fine to unfold has_zero.zero though? My definition of 0 for this type is

def zeros: Π γ, context γ
| [] := nil
| (T::δ) := cons 0 T (zeros δ)

and I need the cons to prove 0+Γ=Γ

view this post on Zulip Wojciech Nawrocki (Jan 22 2019 at 23:21):

In any case this is pretty awesome, all my proofs have shortened by half now without the unfolding, thanks a lot!

view this post on Zulip Mario Carneiro (Jan 23 2019 at 00:37):

For this, you should decide whether you prefer to write the empty context as 0 or [], and write a simp lemma like 0 = [] if you want to get rid of the 0 everywhere. In this case you should also make sure that all your other simp lemmas use the "preferred form" of this element on the LHS

view this post on Zulip Wojciech Nawrocki (Feb 23 2019 at 22:04):

What's the closest thing to the ring tactic when what I have is not a commutative semiring, e.g. just a monoid? Say my theorems are provable simply by repeated application of monoid or group laws, what tactic could I use?

view this post on Zulip Kevin Buzzard (Feb 23 2019 at 22:08):

If it's abelian then abel might work, and if it's not then you're best going with simp I think

view this post on Zulip Kevin Buzzard (Feb 23 2019 at 22:09):

You might have to write simp [mul_assoc] maybe, I can't remember if mul_assoc is a simp lemma

view this post on Zulip Wojciech Nawrocki (Feb 23 2019 at 22:15):

abel worked :) thanks. And no, mul_assoc doesn't seem to be a simp lemma.

view this post on Zulip Wojciech Nawrocki (Feb 23 2019 at 23:41):

Say I would like to work with a particular module which uses a variable v instantiated over a concrete v. For example, a file foo.lean could first declare variable {v: Type} and then use v in all definitions/lemmas in the file. I would like to import everything in foo instantiated with e.g. nat for v. This would be equivalent to partially applying everything in the file to nat. Is such a thing possible without manually redefining everything?

view this post on Zulip Andrew Ashworth (Feb 23 2019 at 23:42):

You could write a tactic to do it

view this post on Zulip Andrew Ashworth (Feb 23 2019 at 23:43):

But, why?

view this post on Zulip Wojciech Nawrocki (Feb 23 2019 at 23:47):

I would like to do this in order to:
a) Avoid type class search by giving it the right instance from the start.
b) Make inference work. I found that making one of my modules more generic (I changed it from using a particular semiring to being generic over arbitrary semirings) broke inference in a lot of places where I use this module because it no longer knows which semiring to pick and I don't want to specify it everywhere manually.
For a more concrete example which is close to what I'm doing, say I define a list inductive slist {α: Type} [semiring α]: Type which is a list the elements of which are also elements of a semiring and then derive a bunch of theorems about the behaviour of such a list under some transformations. I would then like to use all of these theorems only with a particular choice of α, even though the slist file/module is generic.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:06):

But if you're using {alpha : Type} correctly, then Lean should be able to infer what alpha is from subsequent terms, so you don't need to change it to nat, Lean will just guess it for you and do it itself. Have I missed the point?

view this post on Zulip Andrew Ashworth (Feb 24 2019 at 00:15):

"no longer knows which semiring to pick" this sounds fishy

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:18):

The {} brackets aren't type class search, they are dealt with using unification.

view this post on Zulip Wojciech Nawrocki (Feb 24 2019 at 00:23):

You're right, Lean can still unify it and find the class instance - I was perhaps a bit rash there when figuring out what's going on. However, tactic state updates that used to take about 300ms when I was working over a concrete object now take several seconds, making it somewhat painful to work interactively. I was hoping that reinstantiating all the lemmas over the concrete objects again would alleviate this.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:24):

Again, if you're talking about {}s then this isn't to do with classes, it's something else.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:24):

But I agree that sometimes things get slow, and it can sometimes be quite difficult to find out why.

view this post on Zulip Wojciech Nawrocki (Feb 24 2019 at 00:25):

I'm talking about both - the {alpha} variable being unified and [semiring alpha] which needs a class instance.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:25):

Aah yes, that is a class instance. Sorry.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:25):

Does it help to actually put the type class instances explicitly into Lean at the top of the file?

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:26):

e.g. you were working with a random alpha assumed to be a semiring, and now you're working with nat, so you could put instance : semiring nat := by apply_instance at the top of the file. However that instance should already be there so I can't imagine it will help :-/

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:27):

oh this can't be the problem. Unless your actual instances are hard to find.

view this post on Zulip Wojciech Nawrocki (Feb 24 2019 at 00:30):

I couldn't say for sure without benchmarking, but I would guess that the two implicit arguments I added to everything makes it appreciably more difficult to carry out elaboration.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:30):

I'm afraid you'll have to speak to a computer scientist about this one :-)

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:31):

In maths, everything runs instantly.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:31):

You should consider moving to the Platonic universe.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 00:31):

We don't have engineering troubles there.

view this post on Zulip Wojciech Nawrocki (Feb 24 2019 at 00:55):

Oh okay, I ran into the problem that made me think unification fails again. In fact, I believe it could eventually succeed, but currently simp * takes so long it times out, while it would work fine before I added the implicit parameters to one of my modules.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 01:00):

If you want to try to speed things up yourself, you could take a look at what simp was doing before and after by putting logging on.

view this post on Zulip Kevin Buzzard (Feb 24 2019 at 01:01):

set_option trace.simplify.rewrite true is what you need to see what simp is doing.

view this post on Zulip Wojciech Nawrocki (Feb 24 2019 at 23:55):

Does Lean have an equivalent of Haskell's/Agda's where? E.g. def abc := two where two := 2

view this post on Zulip Mario Carneiro (Feb 25 2019 at 00:06):

no

view this post on Zulip Mario Carneiro (Feb 25 2019 at 00:06):

it messes with elaboration order

view this post on Zulip Wojciech Nawrocki (Feb 25 2019 at 00:27):

Could you elaborate on what the issue is?

view this post on Zulip Mario Carneiro (Feb 25 2019 at 00:43):

Lean does pretty much all elaboration from left to right. If you use a postfix let, then the type and value of the defined variable will not be known when it is needed

view this post on Zulip Mario Carneiro (Feb 25 2019 at 00:43):

Is this stupid? Yes. I think lean 4 will relax the elaboration order a bit to allow stuff like this to work

view this post on Zulip Wojciech Nawrocki (Feb 28 2019 at 19:47):

Does anyone know where the extra argument comes from (I do know (n = 0) is probably not valid syntax for a hypothesis)?

def foo_fn := Π (n: ) (n = 0), string

#print foo_fn
/- def foo_fn : Type :=
   ℕ → Π (n : ℕ), n = 0 → string -/
-- ^ what is this?

view this post on Zulip Chris Hughes (Feb 28 2019 at 19:51):

Do you have a variable somewhere in your file?

view this post on Zulip Chris Hughes (Feb 28 2019 at 19:52):

Oh no actually. Π (n = 0), _ is shorthand for Π n, n = 0 -> _

view this post on Zulip Wojciech Nawrocki (Feb 28 2019 at 19:54):

Ah so it is valid syntax. Thanks!

view this post on Zulip Wojciech Nawrocki (Feb 28 2019 at 22:08):

I would like to define a subtype of Lean functions like so:

@[reducible]
def foo_fn :=   

inductive is_foo: foo_fn  Prop
| Id: is_foo (λ x, x)
| Rec: Π {f: foo_fn}, is_foo f  is_foo (λ x, (f x) + 1)

structure foo :=
(f: foo_fn)
(hf: is_foo f)

Where a foo is a ℕ → ℕ together with a proof that it's a valid kind of foo_fn, i.e. either the identity or some other foo plus 1. Then, I would also like to carry out transformations on the foo structure by modifying the foo_fn and adjusting its proof. Unfortunately the foo_fn is opaque as just a Lean function, so to actually do this it seems I need the following:

inductive foo': foo_fn  Type
| Id: foo' (λ x, x)
| Rec: Π {f: foo_fn}, foo' f  foo' (λ x, (f x) + 1)

My question is, can foo' be considered equivalent to foo in the sense that I can extract f: foo_fn out of foo' f and use it as I would use the f member of the structure foo?

view this post on Zulip Kevin Buzzard (Feb 28 2019 at 23:42):

I don't understand the question. Are you not happy with this sort of thing:

def foo_fn :=   

inductive is_foo: foo_fn  Prop
| Id: is_foo (λ x, x)
| Rec: Π {f: foo_fn}, is_foo f  is_foo (λ x, (f x) + 1)

structure foo :=
(f: foo_fn)
(hf: is_foo f)

def add_one : foo  foo :=
λ f, hf, ⟨λ x, f x + 1, is_foo.Rec hf

?

view this post on Zulip Wojciech Nawrocki (Mar 02 2019 at 14:09):

The problem is that I couldn't redefine add_one like this:

def add_one': foo  foo
/- induction tactic failed, recursor 'is_foo.dcases_on' can only eliminate into Prop -/
| f, is_foo.Id := ⟨λ x, f x + 1, is_foo.Rec is_foo.Id
| f, is_foo.Rec hf' := ⟨λ x, f x + 1, is_foo.Rec (is_foo.Rec hf')

And in general any definition which tries to extract an inner foo_fn out of an is_foo constructor will fail, but I need to do that sometimes in order to transform the foo_fn. So far the inductive foo': foo_fn -> Type definition seems to work well though.

view this post on Zulip Kevin Buzzard (Mar 02 2019 at 14:15):

Aah I see; the recursor for is_foo only eliminates into Prop. Yeah you need an expert, not a mathematician :-)

view this post on Zulip Chris Hughes (Mar 02 2019 at 14:26):

The reason this isn't possible in general, is that by proof irrelevance is_foo.Id = is_foo.rec _ if the proofs have the same type, so I cannot define functions that treat these two cases differently.

Since both cases are equal in your function, you can write

def add_one': foo  foo
| f, h := ⟨λ x, f x + 1, is_foo.rec_on h (is_foo.Rec is_foo.Id) (λ hf', is_foo.Rec (is_foo.Rec hf'))

view this post on Zulip Chris Hughes (Mar 02 2019 at 14:28):

Usually this form is preferred however

def add_one' (f : foo) : foo :=
 ⟨λ x, f.1 x + 1, is_foo.rec_on f.2 (is_foo.Rec is_foo.Id) (λ hf', is_foo.Rec (is_foo.Rec hf'))

view this post on Zulip Chris Hughes (Mar 02 2019 at 14:30):

The second add_one' will definitionally reduce in a nice way when applied to an argument f : foo, wherease the first definition will only reduce when applied to an argument of the form ⟨f, h⟩ : foo. This makes the first definition harder to work with in proofs.

view this post on Zulip Wojciech Nawrocki (Mar 02 2019 at 15:12):

Thanks!

view this post on Zulip drocta (Mar 03 2019 at 21:57):

I am trying to say something about free objects, using an existing definition of concrete categories in mathlib.
I couldn't find an existing definition in mathlib for free objects (edit: really, I just need to define free objects over a set or type with one element), so I was going to define them myself.
I have mathlib installed using leanpkg, and it looks like because I have lean version 3.4.1 installed, leanpkg used the branch with that name from the mathlib repository.
However, I notice that the master branch and the 3.4.1 branch have the definition of concrete categories in different places.
Should I go ahead and use the version which is defined in the 3.4.1 branch, and is in the category.lean file, or ought I somehow use the version in the concrete_category.lean version currently in the master branch?

view this post on Zulip Kevin Buzzard (Mar 03 2019 at 22:56):

The master branch of mathlib doesn't work with Lean 3.4.1.

view this post on Zulip Kevin Buzzard (Mar 03 2019 at 22:58):

If I were you I'd use 3.4.2 (probably the last release of Lean 3) and mathlib master. If you install elan then it will all work by magic and you won't have to worry.

view this post on Zulip drocta (Mar 03 2019 at 23:56):

thank you
(edit 7:33 : that worked for me)

view this post on Zulip drocta (Mar 04 2019 at 02:48):

I'm not sure where to find the documentation on out_param . Could you point me towards it?
the definition in core.lean looks like it is just an identity function, but I assume I'm missing something, seeing as I think the lack of it just caused me to get a type error.

view this post on Zulip drocta (Mar 04 2019 at 03:50):

found a way to do what I was trying to do which didn't require that, so nvm I guess?

view this post on Zulip Kevin Buzzard (Mar 04 2019 at 07:03):

out_param is something to do with telling Lean's elaborator what order to do type inference, or something like that. I'm afraid the only documentation that I know of is when I asked for details about it on either this chat or at the old chat, and Mario Carneiro explained it.

view this post on Zulip Kevin Buzzard (Mar 04 2019 at 07:52):

https://gitter.im/leanprover_public/Lobby?at=5a6e31685a9ebe4f75e77351

view this post on Zulip drocta (Mar 05 2019 at 02:35):

out_param is something to do with telling Lean's elaborator what order to do type inference, or something like that. I'm afraid the only documentation that I know of is when I asked for details about it on either this chat or at the old chat, and Mario Carneiro explained it.
https://gitter.im/leanprover_public/Lobby?at=5a6e31685a9ebe4f75e77351

Ah! Thank you!

view this post on Zulip Wojciech Nawrocki (Mar 05 2019 at 14:51):

What is the meaning of this error: rewrite tactic failed, motive is not type correct?
I get it when trying to apply rw [sesh_tp.dual_end_recv] where sesh_tp.dual_end_recv : sesh_tp.dual End? = End! to the following state:

 1(sesh_tp.dual End?)::?m_1 = matrix.identity ((sesh_tp.dual End?) :: γ) End! (ZVar γ End!)

I thought that rw should be able to simply replace the instances of sesh_tp.dual End?.
(End? and End! are constructors for the sesh_tp inductive type.)

view this post on Zulip Patrick Massot (Mar 05 2019 at 15:39):

We need an emoji for this error

view this post on Zulip Patrick Massot (Mar 05 2019 at 15:41):

It means that doing the rewrite will give you an expression which doesn't type check, presumably because you had a dependent type and rewrote the parameter. The classical example is:

set_option pp.notation false
set_option pp.implicit true

example (n m : ) (a : fin (n + m)) (b : fin (n + m)) (h : a = b) : true :=
begin
  rw add_comm at h,

  sorry
end

view this post on Zulip Patrick Massot (Mar 05 2019 at 15:41):

Try understanding this simple example and then your complicated one

view this post on Zulip Wojciech Nawrocki (Mar 05 2019 at 16:04):

Oh right, I get the issue, thanks! But if you rw add_comm both sides of the equation, it should still type check, no? I managed to solve my problem by explicitly stating the type of the goal with both instances of sesh_tp.dual End? rewritten to End!. Could rw not check the type after doing both rewrites?

view this post on Zulip Kevin Buzzard (Mar 05 2019 at 17:52):

rw is what it is. If you want more you can try lots of tricks, e.g. erw or simp only or using conv mode -- we have lots of workarounds :-) But this is dependent type theory, random rewriting can create terms which are not type correct and Lean pulls the plug when this happens.

view this post on Zulip Plam (Mar 05 2019 at 18:58):

Is there a way to make use of the fact that pattern matches in a theorem have the same structure as in a definition? In particular, that given a catchall pattern match later in the theorem, it can't be the case that the thing being matched against matches one of the earlier pattern matches?

Concretely, when proving simp_const_eq below, I want to match on plus (const a) (const b), times (const a) (const b) and then a catchall. Is this possible, or do I just need some extra cases that I can rfl my way through?

inductive aexpr : Type
| const :   aexpr
| var :   aexpr
| plus : aexpr  aexpr  aexpr
| times : aexpr  aexpr  aexpr

open aexpr

def aeval (v :   ) : aexpr  
| (const n) := n
| (var n) := v n
| (plus e₁ e₂) := (aeval e₁ + aeval e₂)
| (times e₁ e₂) := aeval e₁ * aeval e₂

def simp_const : aexpr  aexpr
| (plus (const n₁) (const n₂)) := const (n₁ + n₂)
| (times (const n₁) (const n₂)) := const (n₁ * n₂)
| e := e

theorem simp_const_eq (v :   ) :
   e : aexpr, aeval v (simp_const e) = aeval v e :=
sorry

view this post on Zulip Wojciech Nawrocki (Mar 18 2019 at 01:48):

While I don't think this is possible right now (correct me if I'm wrong), would it in principle be possible to extend Lean with support for custom type unification procedures? The way I defined some inductive families requires me to do a lot of conversions from terms of type T a to a type T b that Lean expects, where a = b. All of these are resolvable more or less with a single tactic, and it would be awesome if I could just teach Lean a heuristic like "If type U is expected and a term of type T is given, see if T or U (or both) contain a specific expression. If so, try to use this tactic to convert T to U".

view this post on Zulip Johan Commelin (Mar 18 2019 at 07:15):

Search the chat for "unification hints"

view this post on Zulip Johan Commelin (Mar 18 2019 at 07:15):

I'm hoping that might be exactly the thing you want. Note however that we don't have much experience with them. Unification hints haven't been used outside of a demo, as far as I am aware.

view this post on Zulip Mario Carneiro (Mar 18 2019 at 07:34):

If by a = b you mean you have a proof that they are equal, not that they are defeq, then unification hints won't help, and a lot of things will get more complicated

view this post on Zulip Wojciech Nawrocki (Mar 18 2019 at 12:38):

@Mario Carneiro indeed by a = b I mean eq a b. What I end up having in the actual terms is a bunch of eq.mprs which do the conversions from T a to T b. My idea here was, could I not just tell Lean to try to insert those conversions automatically when it fails to unify types?

view this post on Zulip Wojciech Nawrocki (Mar 18 2019 at 12:41):

@Johan Commelin I was looking into those but it seems they are not powerful enough to modify the term in question which is what seems to be needed when the types are not algorithmically definitonally equal according to Lean. Moreover, some of the problems that Coq resolves using Canonical Structures, which seem to be a type of unification hint, Lean resolves using type class inference.

view this post on Zulip Kevin Buzzard (Mar 18 2019 at 13:04):

There was some discussion about these issues at Lean Together in January. Note that Lean 4 will apparently be removing unification hints, perhaps because nobody uses them in Lean.

view this post on Zulip Kevin Buzzard (Mar 18 2019 at 13:04):

The speakers who talked about it were Assia Mahboubi and Cyril Cohen, and I am pretty sure their slides are online and linked to here somewhere.

view this post on Zulip Johan Commelin (Mar 18 2019 at 13:05):

See:
https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/unification.20hints/near/158613068

view this post on Zulip Jesse Michael Han (Mar 18 2019 at 14:01):

We also ran into this issue in Flypitch. I found it helpful to have a library of simp lemmas to normalize the location of the casts. I also had the occasional odd experience of being unable to prove an instance of a cast lemma by refl inside a larger proof, but was able to prove that lemma by refl separately, mark it as simp, and then simp would work...

view this post on Zulip Patrick Massot (Mar 18 2019 at 16:18):

Note that Lean 4 will apparently be removing unification hints, perhaps because nobody uses them in Lean.

Is this really clear? I thought that Assia and Cyril provided ample proofs that this would be a tragic mistake. I understand they were removed at the beginning of Lean 4, but many things were removed, and some of them will return at some point. Is there any update on this @Sebastian Ullrich?

view this post on Zulip Sebastian Ullrich (Mar 18 2019 at 16:21):

no

view this post on Zulip Wojciech Nawrocki (Mar 23 2019 at 18:30):

Why does auto_param seem to not work as an implicit argument? I'd like to have a constructor like foo {h: auto_param some_prop ``mytac}: Foo and match on it like | foo rather than | (foo _), but if I put the auto_param in curly brackets, it seems to not actually run the tactic when using def abc := foo - it fails with "failed to synthesize placeholder" rather than trying to run mytac.

view this post on Zulip drocta (Mar 25 2019 at 03:36):

I want the unique function from the type empty to another type. I thought I might be able to do that with empty.rec or empty.rec_on , (going off of the tutorial's use of that with days of the week), but it looks like those both expect to be given a function from empty as an argument, when that is what I'm trying to get.
What am I missing?

view this post on Zulip Johan Commelin (Mar 25 2019 at 05:38):

I think this is what you want:

src/logic/basic.lean:def empty.elim {C : Sort*} : empty  C.

view this post on Zulip Wojciech Nawrocki (Mar 27 2019 at 00:51):

congr gave me the following goal:

γ : precontext,
Γ : context γ,
M : @term γ Γ End?
 @Wait γ Γ M == @eq.mpr (@term γ (Γ + 0) tp.unit) (@term γ Γ tp.unit) _ (@Wait γ Γ M)

Having never worked with heq, I'm not sure if this is provable? Clearly both sides are the same expression, but one has been passed through eq.mpr to cast its type. If it's provable, what would be a good tactic/term to solve it? EDIT: It's probably worth noting that it has been casted to the wrong type, i.e. RHS has the same type as LHS before the cast, but a different one after. Can I undo eq.mpr in here somehow?

view this post on Zulip Wojciech Nawrocki (Mar 27 2019 at 01:25):

Ah h_generalize did it. I would still be interested in hearing if there's a more automated way of doing it.

view this post on Zulip Jesse Michael Han (Mar 27 2019 at 01:30):

cc can sometimes handle heqs of casts which are close to being definitional equalities

view this post on Zulip Jesse Michael Han (Mar 27 2019 at 01:30):

however, it works better when eq.mprs are hidden beneath casts

view this post on Zulip Wojciech Nawrocki (Mar 27 2019 at 01:35):

What's the difference between cast and eq.mpr?

view this post on Zulip Kenny Lau (Mar 27 2019 at 01:37):

@[inline]
def cast : Π {α β : Sort u}, α = β  α  β :=
λ {α β : Sort u} (h : α = β) (a : α), eq.rec a h

@[inline]
def eq.mpr : Π {α β : Sort u}, α = β  β  α :=
λ {α β : Sort u} (h₁ : α = β) (h₂ : β), eq.rec_on _ h₂

view this post on Zulip Wojciech Nawrocki (Mar 27 2019 at 01:40):

Oh, it's just reversed? Okay then :)

view this post on Zulip Kenny Lau (Mar 27 2019 at 01:41):

@[inline]
def eq.mp : Π {α β : Sort u}, α = β  α  β :=
λ {α β : Sort u}, eq.rec_on

view this post on Zulip Kevin Buzzard (Mar 27 2019 at 07:40):

There are people here who would say that if you're dealing with heqs, you're doing it wrong

view this post on Zulip Kevin Buzzard (Mar 27 2019 at 07:40):

Equality of types is evil in type theory

view this post on Zulip Kevin Buzzard (Mar 27 2019 at 07:41):

And maybe you'd be better off making an equiv if you have two types which you have identified in your mind

view this post on Zulip Kevin Buzzard (Mar 27 2019 at 07:41):

Many of the key facts about equality are also proved for equivs

view this post on Zulip Kevin Buzzard (Mar 27 2019 at 07:41):

The key missing one is rw

view this post on Zulip Kevin Buzzard (Mar 27 2019 at 07:42):

But we're working on it

view this post on Zulip Wojciech Nawrocki (Mar 27 2019 at 13:30):

Yeah, I (ab)use dependent types in a way that makes it necessary to prove type equality quite often. I try to give my functions built-in & semi-automated support for this by adding arguments like (h: auto_param (expected_T = actual_T) ``some_tac), but it's not always possible

view this post on Zulip Wojciech Nawrocki (Mar 27 2019 at 14:48):

While I'm at it, how can I rw using a heq? Given Hx: M == x, rw [Hx] tells me that lemma is not an equality nor an iff.

view this post on Zulip Chris Hughes (Mar 27 2019 at 14:49):

With great difficulty. You can try using heq.rec_on, but I think this is usually quite hard, because the resulting expression often won't type check.

view this post on Zulip Simon Hudon (Mar 27 2019 at 15:28):

This is a lesson you have to learn eventually: just because you can write it this way and that it is type correct doesn't mean it's a good idea. Keep the type of your definitions as simple as possible. Move your added logic to separate lemmas or separate definitions.

view this post on Zulip Jesse Michael Han (Mar 27 2019 at 15:47):

heq.subst will let you simulate some rewriting, but as Chris said, it is very painful

view this post on Zulip Kevin Buzzard (Mar 27 2019 at 20:15):

If you know you are abusing dependent types then maybe you are bringing the pain on yourself. I had a maths repo where I used equality of types, because I was learning type theory and didn't understand the difference between equality and definitional equality; I ran into real trouble, which was only fixed by a refactor. What I am pushing for now is a tactic which will rewrite appropriate terms along equivs (or however you say it: if P is a predicate on rings which is mathematically reasonable then for two isomorphic rings R and S, P R will be true iff P S is, and I want a tactic which will show this -- this is something mathematicians do all the time but which seems to be painful in type theory).

view this post on Zulip Wojciech Nawrocki (Mar 27 2019 at 22:27):

@Kevin Buzzard Well, kind of, but not necessarily. I'm still a newcomer to type theory/theorem proving, but from what I read and some discussions I've had, my understanding is that currently Coq can handle these kinds of things much better than Lean. Adding good support for working with dependent types which are only propositionally equal could be well worth the effort. In particular, Coq has a Program framework (which I think I've mentioned here at some point) which is able to find which eqs need to be proven while constructing an expression and generate them as external goals. This way we get a clean expression and all the nasty details are resolved externally. After the goals are proven, Program seems to automatically insert casts, more or less. Moreover, Coq can be told which tactics to use in order to automatically resolve most of such side equality goals. In PVS, I believe these things are called "Type Correctness Conditions" and are also dealt with outside the expression. HoTT also seems to provide an interesting answer to this in the form of paths, but I've only started looking into that.

view this post on Zulip Andrew Ashworth (Mar 28 2019 at 05:56):

Is Program ready for prime time? I only read about it in CPDT, Chlipala is not big on it. http://adam.chlipala.net/cpdt/html/Subset.html

view this post on Zulip Wojciech Nawrocki (Mar 29 2019 at 16:21):

In Coq, JMeq_eq is an axiom, but in Lean eq_of_heq seems to be a lemma with no non-core axioms below it. Does that mean it follows from proof irrelevance or another axiom that Lean has built-in?

view this post on Zulip Mario Carneiro (Mar 29 2019 at 17:56):

@Wojciech Nawrocki Yes, it relies on proof irrelevance.

lemma eq_of_heq {α : Sort u} {a a' : α} (h : a == a') : a = a' :=
have  (α' : Sort u) (a' : α') (h₁ : @heq α a α' a') (h₂ : α = α'), (eq.rec_on h₂ a : α') = a', from
  λ (α' : Sort u) (a' : α') (h₁ : @heq α a α' a'), heq.rec_on h₁ (λ h₂ : α = α, rfl),
show (eq.rec_on (eq.refl α) a : α) = a', from
  this α a' h (eq.refl α)

the rfl on line 3 has type eq.rec_on h₂ a = a, which only makes sense because h₂ : α = α is defeq to rfl by proof irrelevance

view this post on Zulip Wojciech Nawrocki (Mar 29 2019 at 18:16):

Gotcha, thanks!

view this post on Zulip Wojciech Nawrocki (Mar 31 2019 at 18:16):

How can I introduce a new constant into all goals using ;? sometac; have a := 2, doesn't seem to work. EDIT: all_goals { have a := 2 } worked. Unsure why ; doesn't.

view this post on Zulip Chris Hughes (Mar 31 2019 at 18:20):

This worked for me

example : false  false :=
begin
  split; have a := 2,
end

However, this didn't work

example : false  false :=
begin
  split, skip; have a := 2,
end

Maybe the semicolon only works for the goals generated by the last tactic.

view this post on Zulip Rob Lewis (Mar 31 2019 at 18:20):

sometac; have a := 2 works. Remember have is different from let. You'll get a : ℕ in the context, but won't see that it's 2.
Edit: oh, I see the confusion. ; doesn't mean "do the second tactic to all goals." I think t; s means "do t to the first goal, and then do s to all remaining goals."
Edit 2: I'm thinking about too many things at once and writing unclearly, sorry. Chris phrased what I meant better. t; s focuses on the first goal, applies t, and then applies s to all goals generated from that. "Remaining goals" meaning remaining in the focus.

view this post on Zulip Wojciech Nawrocki (Mar 31 2019 at 18:24):

Double-checked, it acts wierdly:

cases h: H; have a := 2, -- works
cases h: H, skip; have a := 2, -- doesn't work
cases h: H, case Foo { .. }; have a := 2, -- doesn't work

view this post on Zulip Reid Barton (Mar 31 2019 at 18:33):

What Chris said. x; y applies y to each goal produced by x.

view this post on Zulip Wojciech Nawrocki (Mar 31 2019 at 18:34):

Oooh, ok! Thanks

view this post on Zulip Wojciech Nawrocki (Mar 31 2019 at 18:41):

Different question - in every goal I have a hypothesis of the form h : hE' = Foo Γₑ' hΓ_1 N E_1 a, where Foo is that goal's case. I would like to solve each goal by applying that goal/case's constructor, but with different arguments. Can I somehow "extract" which constructor was used for the case and reuse it to solve the goal without quoting expressions and all that?

view this post on Zulip Wojciech Nawrocki (Apr 01 2019 at 14:09):

How can I debug a (deterministic) timeout when Lean tries to prove well-foundedness of a recursion given my custom tactic?

view this post on Zulip Wojciech Nawrocki (Apr 01 2019 at 14:13):

Oh actually I also get a "failed to prove well-foundedness" with the state:

h : hE' = EAppLeft Γₑ' hΓ_1 N E_1 a,
Γ : context γ,
M : term Γ A''
 eval_ctx.sizeof
      (((γ,
          Γₑ,
           Γ₁,
            A'',
             A',
              A_1A, E, hE, E_1, a, Γₑ + Γ₁, _⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩.snd).snd).fst)
      (((((((((γ,
                Γₑ,
                 Γ₁,
                  A'',
                   A',
                    A_1A,
                     E,
                      hE,
                       E_1,
                        a,
                         Γₑ + Γ₁,
                          _⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩.snd).snd).snd).snd).snd).snd).snd).snd).fst)
      a <
    eval_ctx.sizeof
      (((γ,
          Γₑ,
           Γₑ',
            A'', A', A, E, hE, E', hE', Γ, hΓ⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩.snd).snd).fst)
      (((((((((γ,
                Γₑ,
                 Γₑ',
                  A'',
                   A',
                    A,
                     E,
                      hE,
                       E',
                        hE', Γ, hΓ⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩⟩.snd).snd).snd).snd).snd).snd).snd).snd).fst)
      hE'

Since h: hE' = EAppLeft ... a is in the context, why can't Lean just rewrite it using that and then show that sizeof a < sizeof EAppLeft .. a?

view this post on Zulip Andrew Ashworth (Apr 01 2019 at 14:47):

this error log is pretty hard to understand just by looking at it

view this post on Zulip Andrew Ashworth (Apr 01 2019 at 14:48):

what always gets linked when these things come up: TPIL and https://github.com/leanprover-community/mathlib/blob/master/docs/extras/well_founded_recursion.md

view this post on Zulip Andrew Ashworth (Apr 01 2019 at 14:55):

what is not mentioned in the mathlib doc is what I usually do when I don't want to stare at a bunch of errors: prove my relation is well-founded by hand well_founded r and directly use well_founded.fix

view this post on Zulip Wojciech Nawrocki (Apr 01 2019 at 15:01):

Oh yeah I'd read that, but was hoping Lean could employ a bit of automation when trying to prove the inequality. I'll try fix as I don't think I can use have( the fn definition is entirely in tactic mode), thanks.

view this post on Zulip Andrew Ashworth (Apr 01 2019 at 15:04):

oh, don't forget http://adam.chlipala.net/cpdt/html/GeneralRec.html

view this post on Zulip Andrew Ashworth (Apr 01 2019 at 15:04):

the definitions are sorta almost the same if you squint

view this post on Zulip snowbunting (Apr 02 2019 at 09:12):

What would be the correct way to define a function from ℤ to (abelian) groups? (i.e. having indexed groups G_1, G_2, ...)

I don't think that this here is working as it should. This would be a constant function, wouldn't it?

universes u
variables {α: Type u}
def my_indexes_groups (i:ℤ) := add_group α
#check my_indexes_groups 3

Thx :)

view this post on Zulip Johan Commelin (Apr 02 2019 at 09:12):

No, because then all groups have the same cardinality

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:12):

You define a function from Z to Type

view this post on Zulip Johan Commelin (Apr 02 2019 at 09:12):

What you do is G : Z → Type

view this post on Zulip Johan Commelin (Apr 02 2019 at 09:13):

And then [\for i, add_group G i]

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:13):

And then you define another function from Z to the structure of a group on the image of the first function :-)

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:14):

And you also note that Lean's definition of add_group doesn't require commutativity so if you're doing exact sequences you might want to use add_comm_group

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:15):

Johan and I are both interested in seeing exact sequences in Lean by the way, we're both mathematicians

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:16):

The way to think about groups in Lean is that they are two things. First you have G, a type

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:16):

And then you have another thing h, a term of type [group G]

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:17):

And it's h that has all the data of the multiplication and the axioms

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:17):

But amazingly you never have to mention h at all when you're working with groups

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:18):

Because whenever Lean needs this data it gets it from G using something called type class inference

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:18):

You try to do a group thing on G like multiplying two elements together

view this post on Zulip snowbunting (Apr 02 2019 at 09:19):

ok that works indeed! Maybe it would be actually ask to ask what the difference between Type and Type u is, although it feels super dumb...

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:19):

And Lean says "what's this multiplication they're talking about? Does my big list of type class stuff contain anything which mentions a multiplication on G? And then it looks and it finds h and says "ok I'll just use that stuff"

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:20):

Type is Type 0

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:20):

In type theory everything has to have a type

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:20):

So unfortunately Type has to have a type

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:20):

Which is Type 1

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:20):

You get the picture

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:21):

Type u is a random universe somewhere up in the hierarchy

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:21):

It's best practice to make functions and constructions take inputs from arbitrary universes in type theory

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:22):

You should do a map from Z to Type u really

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:23):

People might also write Type* -- this is the same thing, it just saves you having to name u

view this post on Zulip snowbunting (Apr 02 2019 at 09:28):

ok so u really is just a number, like Type u one of Type 0, Type 1, ...
And if I don't want to force two variables to be both for example Type 2 simultaneously, then I should use Type u and Type v in the definition, right?

And if I would write def xxx (a: Type*) (b: Type*): Type* := sorry then there is no constrains if they have the same type or not, is there?

Thx :)

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:28):

That's right.

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 09:29):

u is a natural number, but it's not a Lean natural number, it's a universe variable, which is treated differently; it's part of the core language or something.

view this post on Zulip snowbunting (Apr 02 2019 at 14:53):

And then [\for i, add_group G]

This works great together with variable, but how would I now include that into a class? This does not seem to be working:

universe u
class chain (α: Type u) :=
    (group (i:): Type u)
    (diff {i:}: (group i)  (group (i-1)))
    [x: i, add_comm_group (group i)]

variable (C: Type)
variable [chain C]
variables (g h: chain.group C 1)

#check g
#check chain.group C 1
#check chain.diff g
#check g + h    -- has_add (chain.group C 1)

view this post on Zulip Johan Commelin (Apr 02 2019 at 14:54):

Put it with () in the class. Then aftwerwards state:

instance foo (i : ) : add_group C i := C.x i

view this post on Zulip Johan Commelin (Apr 02 2019 at 14:54):

Modulo mistakes

view this post on Zulip Johan Commelin (Apr 02 2019 at 14:56):

Also, you might be interested in category_theory/

view this post on Zulip snowbunting (Apr 02 2019 at 14:56):

Of course, I should have remembered instance, used that before, thank you!

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 17:59):

Your alpha doesn't do anything

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 17:59):

You could just remove it, and you could change class to structure

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 18:01):

Then a term of type chain would be a bunch of abelian groups and homs

view this post on Zulip Kevin Buzzard (Apr 02 2019 at 18:01):

You use class when there's only expected to be one term of that type

view this post on Zulip Scott Morrison (Apr 02 2019 at 22:05):

Also, you might be interested in category_theory/

Regarding initial experiments, this isn't meant at all as discouragement --- but eventually we'd like the definition of chain_complex to be as generic as possible (e.g. any category enriched in a category with_zero).

view this post on Zulip Wojciech Nawrocki (Apr 05 2019 at 20:42):

Is there anything I can do to debug "equation compiler failed to prove equation lemma (workaround: disable lemma generation using set_option eqn_compiler.lemmas false)"?

view this post on Zulip Kevin Buzzard (Apr 05 2019 at 21:10):

Wow that's some error! How did you get that?

view this post on Zulip Patrick Massot (Apr 05 2019 at 21:11):

Kevin is so jalous...

view this post on Zulip Wojciech Nawrocki (Apr 05 2019 at 22:24):

:) It happens in this definition (link)

view this post on Zulip Kevin Buzzard (Apr 05 2019 at 22:31):

it doesn't compile for me because it needs imports I don't have :-/

view this post on Zulip Kevin Buzzard (Apr 05 2019 at 22:31):

but even if it did compile for me I think I wouldn't be able to help.

view this post on Zulip Wojciech Nawrocki (Apr 05 2019 at 23:04):

Oh, it's self-contained modulo downloading mathlib, but for some reason leanpkg.path was in my .gitignore and it's needed for import paths to resolve - fixed that

view this post on Zulip Reid Barton (Apr 05 2019 at 23:31):

leanpkg.path should indeed be in .gitignore (assuming you are actually using leanpkg)

view this post on Zulip Mario Carneiro (Apr 06 2019 at 02:15):

Is it related to the use of let in the type of the function you are defining by pattern matching?

view this post on Zulip Wojciech Nawrocki (Apr 06 2019 at 21:09):

@Mario Carneiro it doesn't seem like it, I can inline the let, same error

view this post on Zulip Mario Carneiro (Apr 06 2019 at 21:10):

do you have a self contained MWE?

view this post on Zulip Mario Carneiro (Apr 06 2019 at 21:10):

(Try putting everything needed in one file, then start deleting things that don't matter for the error)

view this post on Zulip Wojciech Nawrocki (Apr 09 2019 at 19:57):

@Mario Carneiro thanks, that was good idea! It took a while but I was able to simplify it to this:

inductive foo:     Type
def foo_fn (n m: ): Type := foo n m  foo n m

inductive is_foo_fn
  : Π {n m: }, foo_fn n m  Type
| IsFooEta:
  Π {n m: } {f: foo_fn n m},
  is_foo_fn f
 is_foo_fn (λ M, f M)
open is_foo_fn

def ext: -- equation compiler failed to prove equation lemma (workaround: disable lemma generation using `set_option eqn_compiler.lemmas false`)
    Π {m n: }
      {f: foo_fn n m},
    is_foo_fn f
   Σ f': foo_fn n m, is_foo_fn f'
| _ _ _ (IsFooEta f) :=
  ⟨_, IsFooEta (ext f).snd

which still fails, while making the following change makes the eqn compiler work:

def ext: -- good
    Π {n m: }
      {f: foo_fn n m},
    is_foo_fn f
   Σ f': foo_fn n m, is_foo_fn f'
| _ _ _ (IsFooEta f) :=
  ⟨_, IsFooEta (ext f).snd

Can you spot the difference? :) (it's the order of arguments). To me this seems like an eqn_compiler bug
And indeed this stupid-simple fix works on my actual code :D

view this post on Zulip Wojciech Nawrocki (Apr 09 2019 at 20:30):

@Sebastian Ullrich What do you think? Is this a bug or am I missing something obvious?

view this post on Zulip Kevin Buzzard (Apr 09 2019 at 20:31):

Thanks for putting in the effort. I've never seen this error before.

view this post on Zulip Sebastian Ullrich (Apr 09 2019 at 20:34):

Me neither

view this post on Zulip Patrick Massot (Apr 09 2019 at 20:34):

Can you reproduce it in Lean 4?

view this post on Zulip Patrick Massot (Apr 09 2019 at 20:35):

If not, then who cares about this error?

view this post on Zulip Kevin Buzzard (Apr 09 2019 at 20:39):

those of us who are stuck with Lean 3?

view this post on Zulip Kevin Buzzard (Apr 09 2019 at 20:39):

;-)

view this post on Zulip Andrew Ashworth (Apr 09 2019 at 22:42):

I don't have time to look into this deeply, but just remarking that I have seen 'equation compiler failed to prove equation lemma' before

view this post on Zulip Andrew Ashworth (Apr 09 2019 at 22:42):

a very long time ago, I think the last time I saw it there was some problem with eta reduction

view this post on Zulip Andrew Ashworth (Apr 09 2019 at 22:43):

but i could be hallucinating how I fixed it, since it was awhile ago

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 09:51):

Given

def P (n: ) : Prop := n > 42

example (n: ) : P n = (P (nat.succ n)) := -- this is obviously false
begin
unfold P, -- this unfolds both occurrences
sorry
end

how can I unfold P just at the right-hand side?

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:52):

you can just use change or show

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:53):

def P (n: ) : Prop := n > 42

example (n: ) : P n = (P (nat.succ n)) := -- this is obviously false
begin
  show P n = ((nat.succ n) > 42),
sorry
end

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:54):

If you're planning on using the rw tactic, then Lean might be very fussy about exactly which form a term is in

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:55):

but conversely Lean is happy to switch between definitionally equal forms of the same term, using the change and show tactics (which do the same thing, change having the advantage that it also works for hypotheses in your context with change ... at H)

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 09:55):

Ah okay, thanks. If my goal statement is very long though, I end up copy-pasting a lot of text.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:56):

there are other ways

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:57):

def P (n: ) : Prop := n > 42

example (n: ) : P n = (P (nat.succ n)) := -- this is obviously false
begin
  conv begin
    to_rhs,
    simp only [P],
  end,
sorry
end

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:57):

conv mode is a mode which isn't mentioned at all in the official docs

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:57):

It enables you to zoom into parts of terms

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:58):

Unfortunately, when you're in conv mode, the tools available to you are completely different, and it doesn't look like unfold is available yet.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:58):

So I had to use simp only

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:58):

which is close to the same thing

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 09:58):

uuh, the hidden secrets. that does not seem very elegant to me though :')

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:58):

The community documented conv mode.

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 09:58):

I though I could make use of some pattern matching or occurrence counting when I was reading https://leanprover.github.io/tutorial/A1_Quick_Reference.html A1.6.2.1

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 09:59):

But I am either to silly or misinterpreting what is written there.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 09:59):

https://github.com/leanprover-community/mathlib/blob/master/docs/extras/conv.md

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:00):

Your link there is to an out of date file :-/ That's Lean 2 you're looking at

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:00):

You can use conv to zoom directly into the right hand side with conv in or conv at or something, I can never remember the details, but they're clearly documented in Patrick's conv.md write-up

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 10:01):

Oh damn, google fooled me

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:01):

That way you avoid the to_rhs conv-mode tactic

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:01):

Oh damn, google fooled me

call them up and complain

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:02):

example (n: ) : P n = (P (nat.succ n)) := -- this is obviously false
begin
  conv in (P (nat.succ n)) begin
    simp only [P],
  end,
sorry
end

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:03):

def P (n: ) : Prop := n > 42

example (n: ) : P n = (P (nat.succ n)) := -- this is obviously false
begin
  rw (show P (nat.succ n) = (nat.succ n > 42), from rfl),
sorry
end

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:03):

This way avoids conv mode and is more precise about what you want done

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:04):

What exactly are you looking for? Tactic-writers here are very good.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:04):

People can just make new stuff. Lean tactics are written in Lean and some people (not me though! I'm a mathematician) can just knock them off before breakfast.

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 10:11):

Basically, I had a rather long equation of the form l=r and I wanted to unfold an expression in r by its definition, which again, is a rather long term. Hence, I neither want to re-state the whole goal nor the result of the unfolded definition. What I want to do is something like

begin
unfold P {2} -- this should unfold the second occurrence of P in the goal (or the third if you count from zero)
sorry
end

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:12):

@Gabriel Ebner is that already a tactic, do you know?

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:12):

Is there any obstruction to making it?

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:14):

@Kevin Kappelmann you could just do all the unfolds manually, ignore what happens to l, and then once you've got r into the form you want you can just delet everything and write show _ = [what you want r to be]

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:14):

(the point being that show will take _ for the left hand side)

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:16):

I think I've now told you all the tricks I know -- but I can see that your proposed idea is nicer. It might be a pain though -- if you want to unfold a bunch of stuff in r but not in l you might have to keep changing the numbers, depending on which things you want to unfold in r also show up in l. I think that if you're adamant that you want to change r and leave l untouched, just use conv mode and to_rhs. That's only a couple of lines and I think it's better than your idea because of the issue with numbers perhaps changing depending on exactly you want to unfold.

view this post on Zulip Gabriel Ebner (Apr 18 2019 at 10:17):

Yes, you can do this with conv. Unfortunately, unfold isn't wrapped so you need to use simp.

conv { for (P _) [2] { simp [P] } },

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:17):

OTOH I guess your idea has its merits when there is more than one occurrence of P in the RHS.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:17):

Aah, I'd forgotten conv could take numbers!

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:17):

Thanks Gabriel

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:18):

hey what is this voodoo? for? I thought functional languages didn't have for loops!

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:20):

Aah yes, I see now that for is documented in the conv document I linked to earlier.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:20):

It's about time I re-read it :D

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:22):

I'll show you a Lean trick Kevin.

def P (n: ) : Prop := n > 42

#print prefix P

-- P.equations._eqn_1 : ∀ (n : ℕ), P n = (n > 42)

When you define P, Lean makes one or more "equation lemmas" for it. unfold P is basically the same as simp only [P.equations._eqn_1] or simp only [P] for short. It's a shame there's no unfold in conv mode, but these are the tricks you can use to emulate it.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:23):

def P (n: ) : Prop := n > 42

example (n: ) : P n = (P (nat.succ n)) := -- this is obviously false
begin
  rw P.equations._eqn_1 (nat.succ n),
  sorry
end

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 10:23):

Okay, I summarise: conv is pretty useful, I should read about it, and I guess it should also be included in the official docs at some point to avoid noobs like me wondering how to rewrite subterms :p

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:24):

The Lean team is currently working on Lean 4, I don't think they're interested in documentation-writing at the minute.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:24):

If Lean 4 is a success then we'll all be porting the docs over to there

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:25):

The community-written docs are really helpful for technical questions not covered by Theorem Proving In Lean.

view this post on Zulip Kevin Buzzard (Apr 18 2019 at 10:25):

They all live in the mathlib repo but they're not really anything to do with mathlib, they're just where these community-generated docs ended up.

view this post on Zulip Kevin Kappelmann (Apr 18 2019 at 10:29):

I see. I think rewriting subterms is quite common though, so I would mention it at least in the official doc. Anyway, thanks Kevin & Gabriel :)

view this post on Zulip Jesse Michael Han (Apr 18 2019 at 12:52):

you can use underscores with change and Lean will try to infer what should be there from the current goal. that way change _ = new_rhs lets you avoid copy-pasting the entire left hand side

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:24):

How would I go about proving ∀ x : ℤ, even x ∨ odd x? I have even and odd as
def even : ℤ → Prop := λ n, ∃ m : ℤ, 2*m = n
def odd : ℤ → Prop := λ n, ∃ m : ℤ, 2*m + 1 = n
I assume that I would first have to show that odd is equivalent to not even, then apply classical.em. However, I'm having trouble proving odd x ↔ ¬(even x)

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:28):

My instinct would be to prove even n -> odd (n+1) etc, and then prove by induction that every integer was odd or even.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:28):

There are induction hypotheses of the form (P 0 and (forall n, P n -> P(n+1)) and (forall N, P(n)->P(n-1))) implies P(n) for all n

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:29):

Ah, I see. That makes sense. I'm not familiar enough with induction in Lean yet, but I'll try it out

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:29):

thank you, I'll respond again if I'm stuck on the inductive bit

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:29):

If you just apply the induction tactic out of the box, you'll get an unpleasant surprise

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:30):

You'll end up with some question about natural numbers instead, and it will be pain converting from naturals to integers.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:30):

You'll need to find an appropriate custom induction term in the library.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:31):

Oh, okay. I'm not familiar enough with the library to get started with that. Where would I go to look for something like that?

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:31):

int.induction_on should be fine for you.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:33):

import data.int.basic at the top of your file (you'll need the maths library mathlib) and then apply that function, and you'll be left with goals of the form "n even or n odd -> n+1 even or n+1 odd" which you should be able to cope with. Prove n even -> n+1 odd and the other three results (e.g. n odd -> n-1 even) first and then use them all to prove the result.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:34):

Neat. I have mathlib, but I find most of the algebra/analysis files unreadable despite being highly competent with the material on paper. Are there any other packages you would recommend before diving into that level of material?

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:36):

I would recommend doing just what you're doing -- writing material yourself. I agree that the library is impenetrable for a beginner. Proofs are specifically shortened for efficiency reasons, they are not written to be readable. We are still lacking a bunch of good teaching material for mathematicians; I intend to make some this summer, however I also said that last summer.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:38):

Here's me trying to do some problem sheets which we give to 1st year mathematicians at Imperial: https://github.com/ImperialCollegeLondon/M1F_example_sheets

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:39):

Oh wow, that's a substantial amount of material. Thank you so much!

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:40):

The proofs are written in a far more longwinded way, they might be more instructional but there are still not many comments.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:40):

You can step through them in tactic mode and watch the state change, of course.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:42):

Right, I think that as long as I can just run through the tactic state I should be fine. Are there solutions for every single exercise?

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:44):

Also, despite there being a real numbers package in mathlib, I've never seen it before. That's super useful!

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:45):

oh wow, there's also complex numbers defined. That's amazing

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:45):

I don't think I managed every single exercise. There were some which were hard to formalise.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:46):

Those answers are really just a big work in progress. They were just me trying to figure out if Lean was ready for a beginning undergraduate level maths course. It was.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:46):

Are you a professor at Imperial?

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:46):

Yes

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:47):

Oh, that's awesome. I'm just an undergrad math student

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:48):

I felt like that when I was trying to get Lean to do my own problem sheets.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:50):

Haha yeah, the professor here at UVA has a tough time teaching Lean. It seems like it's one of those things where many trivial proofs on paper are just very difficult to formalise, despite familiarity

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:51):

Yes. I spent about a year being very frustrated with not being able to make Lean do obvious things. I'm now finally over that initial learning hump and I can write even research level maths in Lean now, although it can take a long time.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:53):

Well congrats. I hope to get to that point someday. What maths research have you been able to formalise in Lean?

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:53):

https://github.com/leanprover-community/lean-perfectoid-spaces

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:53):

It's not finished yet but we're getting there.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:54):

I've just spent the last 30 minutes staring at https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Cute.20lemma/near/163135381

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:54):

some technical lemma about topological spaces which we need.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:55):

that's... absolutely amazing. I never imagined we could do something like this in Lean so soon.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:55):

Yeah me neither

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:55):

I've had a huge amount of support from other people here

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:56):

18 months ago there weren't even complex numbers

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:56):

Now we have schemes https://github.com/ramonfmir/lean-scheme and they work

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:56):

Wow. Yeah, I'm now very happy that I've been introduced to this chat by Dr. Hölzl

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:56):

Oh wow, algebraic geometry? I'll have to tell my advisor about this

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:57):

we have stuff which reflects the interests of the people involved, I guess.

view this post on Zulip Greg Conneen (Apr 21 2019 at 17:58):

Thank you so much for all this info. I really appreciate it. I look forward to participating more in the future, when I get a little bit more acquainted with Lean.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:58):

https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Taking.20the.20Stacks.20Project.20formalisation.20forward

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:58):

That's the schemes thread

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:58):

we're going to re-write it using the category theory library; at the minute we make all the categories by hand.

view this post on Zulip Kevin Buzzard (Apr 21 2019 at 17:59):

There are universe issues, as ever in category theory, so it gets a bit hairy because you have to do it all properly in a system like this

view this post on Zulip Greg Conneen (Apr 21 2019 at 18:00):

That makes sense. Cat theory makes for the introduction of some interesting nuances

view this post on Zulip Greg Conneen (Apr 21 2019 at 18:14):

How do I apply one direction of an iff? Like, if I wanted to only apply the left implication in a proof.

view this post on Zulip Mario Carneiro (Apr 21 2019 at 18:36):

bla.1 or bla.mp

view this post on Zulip Mario Carneiro (Apr 21 2019 at 18:36):

which is short for iff.mp bla

view this post on Zulip Greg Conneen (Apr 21 2019 at 18:37):

oh okay, so if my iff statement was titled bla, bla.1 would be the left implication, and bla.2 would be the right?

view this post on Zulip Greg Conneen (Apr 21 2019 at 18:48):

Also, where can I find the xenalib package?

view this post on Zulip Greg Conneen (Apr 21 2019 at 18:50):

nvm, found it

view this post on Zulip Greg Conneen (Apr 22 2019 at 13:02):

Okay, I've got a Lean file I've tinkered around with in the past, which includes some simple proofs about integers. Some propositions I've failed to prove in Lean, and the rest I'm sure are anything but efficient. I was wondering if anyone would be willing to look over this file for me and give me some pointers on how to improve my proving techniques. int_props.lean

view this post on Zulip Greg Conneen (Apr 22 2019 at 13:03):

It's sort of a long file, and not very organised, but any help at all would be really appreciated. Sorry in advance.

view this post on Zulip Greg Conneen (Apr 23 2019 at 06:12):

I'm having trouble defining structure fields. The generic construction of structures is fine, I just don't understand fields. How would I go about appending them to a given structure?

view this post on Zulip Johan Commelin (Apr 23 2019 at 06:16):

Do you mean extending a structure?

view this post on Zulip Johan Commelin (Apr 23 2019 at 06:16):

Search for "extend" in mathlib and you will find lots of examples

view this post on Zulip Greg Conneen (Apr 23 2019 at 06:41):

oh, cool. Thank you. I didn't even know what I was looking for until you showed me

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 06:58):

You might want to read the chapters on inductive types and structures in TPIL.

view this post on Zulip Patrick Massot (Apr 23 2019 at 07:22):

@Greg Conneen what Kevin really means is: if you have any interest in learning Lean, you want to read all of TPIL. The modern way of doing that is to launch VScode, open any Lean file, type Ctrl-shift-p type lean, select "Open documentation view", click "Theorem proving in Lean". This way you can click "Try it!" links on code snippets to open them right in VScode and play with them.

view this post on Zulip Patrick Massot (Apr 23 2019 at 07:32):

Trying to figure out the community map: Greg, are you a student of the Kevin Sullivan?

view this post on Zulip Greg Conneen (Apr 23 2019 at 12:47):

I was Prof. Sullivan's student last year, yes.

view this post on Zulip Greg Conneen (Apr 23 2019 at 12:49):

I've read the entirety of TPIL. I'm just still having trouble with implementation. I guess I'll tinker around with it a bit more

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:09):

Okay, so if a group is defined like this

structure group : Type u  Type u
fields:
group.mul : Π {α : Type u} [c : group α], α  α  α
group.mul_assoc :  {α : Type u} [c : group α] (a b c_1 : α), a * b * c_1 = a * (b * c_1)
group.one : Π (α : Type u) [c : group α], α
group.one_mul :  {α : Type u} [c : group α] (a : α), 1 * a = a
group.mul_one :  {α : Type u} [c : group α] (a : α), a * 1 = a
group.inv : Π {α : Type u} [c : group α], α  α
group.mul_left_inv :  {α : Type u} [c : group α] (a : α), a⁻¹ * a

the way I would make something like this would be

structure {u} fake_group (a : Type u) :=
(mul : Π {α : Type u} [c : group α], α  α  α)
...

except, I want to change group α to fake_group α and I don't understand how to do that. I also in general don't understand the bracket notation or what pi does.

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:14):

Note, you can use

```lean
foobar
```

to get code blocks with syntax highlighting

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:15):

oh okay, thanks

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:16):

Note that a group is not defined the way you did. (Internally that is what Lean sees, maybe. But it isn't how it's written in the Lean source files.)

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:16):

Tip: write #print group in VScode, and Ctrl-click on group.

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:16):

Or put your cursor on group and hit Ctrl - Shift - F10

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:17):

ohhhh I see. So a group is simply an extension of a monoid, which I assume is an extension of a semigroup.

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:18):

...which it is, 4 lines above. Thank you so much.

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:22):

So, in general, classes are used in the backend, but Lean interprets them as structures. What's the difference?

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:23):

Also, is there any way to formalise has_mul and has_one without extending those classes?

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:24):

No the difference between classes and structures is type class inference

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:24):

Also, is there any way to formalise has_mul and has_one without extending those classes?

Just copy paste their definitions.

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:24):

I don't know what you mean by that

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:24):

The word class is a red herring in this discussion

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:24):

You could write structure everywhere

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:25):

gotcha. So the only difference is that structures are't able to inherit the properties of other structures. So when would you use a structure over a class?

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:26):

No, structures can inherit

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:26):

The difference is "type class instance". Search for that in TPIL.

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:26):

oh. Then what do you mean by "type class inference?"

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:27):

oh okay, gotcha

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:27):

must've skimmed over that section

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:27):

inference, not inheritance :wink:

view this post on Zulip Johan Commelin (Apr 23 2019 at 13:27):

/me never read TPIL in detail. I'm a cargo cult Leaner.

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:27):

The difference between a structure and a class is that classes are structures with extra magical sauce.

view this post on Zulip Greg Conneen (Apr 23 2019 at 13:27):

Ah, that's my confusion. Thank you for being patient with me

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:27):

I was trying to write some advanced notes on type class inference

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:28):

but before I wrote them I wrote some basic notes on type class inference for mathematicians

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:28):

These might help. They present the same material as in TPIL but in a way far more suited to mathematicians.

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:28):

They're in a branch of mathlib, hang on, I'll dig it out. I'm actually on an aeroplane at this point

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:32):

https://github.com/leanprover-community/mathlib/blob/kbuzzard_typeclass_inference_doc/docs/extras/typeclass_inference.md

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:33):

I found typeclass inference really hard to learn. It was only when I began to try to do normal maths in Lean that I began to see the point of it and understand it properly.

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 13:36):

For reasons that you don't need to worry about and which might change, Lean keeps a ring in two packages not one. The first is a type called something like R. The second is a whole bunch of data which might be called something like _inst_1 : ring R and which you should never need to look at, but it's here that all the multiplication and the addition and the zero and the axioms are all stored. You will probably not need to dig out the axioms, you should just be applying lemmas, if you're doing mathematics -- but sometimes it's important to know where Lean magics up e.g. the proof of the distributivity law for the integers, and if you want to know this then you need to know about typeclass inference.

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:10):

What if I wanted to talk about a ternary operator instead of a binary one (I want to define an algebraic heap)? I can't use has_mul, since it's strictly binary...

view this post on Zulip Andrew Ashworth (Apr 23 2019 at 14:12):

yup

view this post on Zulip Andrew Ashworth (Apr 23 2019 at 14:13):

what exactly is your question about ternary operators?

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:17):

I want to define a class, let's start with semiheap. I only need it to have the following property, called para-associativity:

forall a b c d e : alpha, [[a b c] d e] = [a [d c b] e] = [a b [c d e]]

where [a b c] is a ternary operator. Although, If I have to use different notation given Lean's use of square brackets, that's fine

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:19):

I assume I have to define some sort of infix for a ternary operator, but I don't know how to implement that

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:19):

Does the operator have a "canonical" name in the literature?

view this post on Zulip Andrew Ashworth (Apr 23 2019 at 14:19):

section 10.3 in TPIL describes notation

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:19):

You will first want to define it without the ternary notation.

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:19):

Afterward, you can define the notation, and start using it.

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:20):

Okay. I assume that I need to give it an operation on 3 elements, then state the rule

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:21):

And no, unfortunately there's not really a canonical name for the operator. It's just a ternary operation, in the same way that the standard operation a group deals with is just a binary one

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:22):

Yup. So you want fields

(tern_op : X  X  X  X)
(semi_assoc : \for a b c d e, blabla)

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:22):

And no, unfortunately there's not really a canonical name for the operator. It's just a ternary operation, in the same way that the standard operation a group deals with is just a binary one

We "canonically" call it multiplication.

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:23):

Ah, I see. That makes sense. Although, most mathematicians I know don't like to be so restrictive in terminology :P

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:23):

I was just wondering whether there was a good alternative to tern_op.

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:24):

Yeah, I figured that's what you were after. Heaps aren't really a common algebraic structure, I'm really just trying to implement this so I have a better understanding of how Lean deals with structures/classes

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:29):

Also, am I able to say that 3 things are equal in one field without using "and"?

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:29):

like how I wrote above

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:31):

there are stupid indirect ways to say it, but using and is the reasonable one

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:32):

Okay. Unfortunate, but I guess it's better than defining two separate fields

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:33):

If you really want to you can build an API around this

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:34):

No thank you lol

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:34):

You will need lemmas about heaps saying that anyway

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:35):

Whatever is inside your field, you'll want a lemma asserting the three relevant equalities

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:35):

I don't know what you mean

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:36):

Why would I need a lemma? Are you talking about showing that some object is a heap?

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:36):

I'd expect that just implementing the classes wouldn't require lemmas

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:36):

No, he is talking about making it usable

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:37):

Oh, okay. So I can't refer to the fields until I define lemmas for them?

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:39):

You will have:

class heap {X : Type*} :=
...

namespace heap
variables {X : Type*} [heap X] (a b c d e : X)
lemma assoc1  : [[a b c] d e] = [a [d c b] e] := sorry

lemma assoc2  : [a [d c b] e] = [a b [c d e]] := sorry

lemma assoc3  : [[a b c] d e] = [a b [c d e]] := sorry
end heap

view this post on Zulip Chris Hughes (Apr 23 2019 at 14:39):

I would have three fields rather than an and

view this post on Zulip Johan Commelin (Apr 23 2019 at 14:39):

You can refer to them, otherwise you can't state the lemmas. What Patrick is saying is that with only the fields you'll have something that is cumbersome to use.

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:39):

yeah I'm putting it into 3 fields. I've realised that's easier

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:39):

The point is: whatever the implementaion chosen, after writing those three lemmas, you will have your three equalities

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:40):

What does that change? Just being able to refer to the property without using semiheap.*?

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:40):

Of course if you put all three lemmas as fields then you don't have to state theses lemmas to use them (unless for some reason you want to change binder types, but that's a more advanced discussion)

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:41):

Also, is Type* a way of referring to an arbitrary Type level without defining a universe?

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:41):

And if you use redundant fields like that you will probably want a custom constructor

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:43):

How would a custom constructor help me?

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:43):

Sorry, but I'm still very new, and I don't really see the big picture yet

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:45):

I think the discussion would be much easier if you write something and then we comment it

view this post on Zulip Patrick Massot (Apr 23 2019 at 14:45):

Abstract discussion won't help

view this post on Zulip Greg Conneen (Apr 23 2019 at 14:45):

Yeah I agree. I'll post in just a second

view this post on Zulip Greg Conneen (Apr 23 2019 at 15:00):

This is what I've got so far:

class semiheap (α : Type*) :=
(tern_op : α  α  α  α )
(para_assoc1 :  a b c d e : α,
    tern_op (tern_op a b c) d e = tern_op a (tern_op d c b) e)
(para_assoc2 :  a b c d e : α,
    tern_op (tern_op a b c) d e = tern_op a b (tern_op c d e))
(para_assoc3 :  a b c d e : α,
    tern_op a (tern_op d c b) e = tern_op a b (tern_op c d e))


namespace semiheap
notation `[` _ _ _ `]` := λ x y z : α, tern_op x y z
variables {α : Type*} [semiheap α] (a b c d e : α)

lemma para_assoc1 : sorry := sorry
lemma para_assoc2 : sorry := sorry
lemma para_assoc3 : sorry := sorry
end semiheap

The semiheap as defined is fine. I'm just having trouble with the notation, since it throws an error saying I'm referencing local variables if I put it below them, and I don't know how to reference the semiheap alpha if I put it above.

view this post on Zulip Patrick Massot (Apr 23 2019 at 15:12):

I don't think you can use space as a delimiter in this notation. You can play with

class semiheap (α : Type*) :=
(tern_op : α  α  α  α)
(notation `[` x `|` y `|` z `]` := tern_op x y z)
(para_assoc1 :  a b c d e : α, [[a | b | c] | d | e] = [a | [d | c | b] | e])
(para_assoc2 :  a b c d e : α, [a | [d | c | b] | e] = [a | b | [c | d | e]])
(para_assoc3 :  a b c d e : α, [[a | b | c] | d | e] = [a | b | [c | d | e]])


def semiheap.mk' {α : Type*} (op :α  α  α  α)
(h1 :  a b c d e : α,
    op (op a b c) d e = op a (op d c b) e)
(h2 :  a b c d e : α,
    op (op a b c) d e = op a b (op c d e)) : semiheap α :=
{ tern_op := op,
  para_assoc1 := h1,
  para_assoc2 := λ a b c d e, (h1 a b c d e)  (h2 a b c d e),
  para_assoc3 := h2}

view this post on Zulip Patrick Massot (Apr 23 2019 at 15:13):

The function is the custom constructor, it lets you build a structure by providing only two equalities

view this post on Zulip Greg Conneen (Apr 23 2019 at 15:16):

Why have we defined .mk'? What does it do? Also, what is ▸?

view this post on Zulip Patrick Massot (Apr 23 2019 at 15:17):

Please first try to define an instance of semiheap

view this post on Zulip Greg Conneen (Apr 23 2019 at 15:17):

It clearly rewrote, but what does it do in general?

view this post on Zulip Greg Conneen (Apr 23 2019 at 15:17):

Okay, I will

view this post on Zulip Greg Conneen (Apr 23 2019 at 16:01):

I've got it.

def tern_add :        := λ a b c, a+b+c
instance int_semiheap : semiheap  :=
begin
apply semiheap.mk' tern_add,
rw tern_add,
simp,
rw tern_add,
simp,
end

view this post on Zulip Greg Conneen (Apr 23 2019 at 16:01):

Thank you so much for your help.

view this post on Zulip Patrick Massot (Apr 23 2019 at 16:06):

Does that code compile?

view this post on Zulip Patrick Massot (Apr 23 2019 at 16:07):

Anyway, the point is you had to prove only para-associativity equalities instead of three

view this post on Zulip Patrick Massot (Apr 23 2019 at 16:07):

You can also study (after adding import tactic.abel on top of your file):

def tern_add :        := λ a b c, a+b+c

example : semiheap  :=
{ tern_op := tern_add,
  para_assoc1 := by { intros, dsimp[tern_add], abel },
  para_assoc2 := by { intros, dsimp[tern_add], abel },
  para_assoc3 := by { intros, dsimp[tern_add], abel } }


example : semiheap  :=
semiheap.mk' tern_add (by { intros, dsimp [tern_add], abel }) (by { intros, dsimp [tern_add], abel }

view this post on Zulip Patrick Massot (Apr 23 2019 at 16:08):

you can also replace dsimp [tern_add] by unfold tern_add

view this post on Zulip Greg Conneen (Apr 23 2019 at 16:10):

Okay, I will. I'm currently implementing heaps as an extension of semiheaps. How do I avoid having to write the notation as a field over and over?

view this post on Zulip Patrick Massot (Apr 23 2019 at 16:12):

you need to reissue the notation command after the semiheap definition. The one inside the definition has limited scope

view this post on Zulip Greg Conneen (Apr 23 2019 at 16:12):

Gotcha. So at most I'll only have to write it twice

view this post on Zulip Patrick Massot (Apr 23 2019 at 16:13):

yes

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:07):

Is the symmetric group defined anywhere in mathlib? If not, I'd like to go about implementing it, and in doing so would need some guidance

view this post on Zulip Johan Commelin (Apr 23 2019 at 19:08):

It is:

src/data/equiv/basic.lean:/-- `perm α` is the type of bijections from `α` to itself. -/

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:09):

Thank you

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:10):

Followup question, has Cayley's theorem been proven?

view this post on Zulip Johan Commelin (Apr 23 2019 at 19:13):

@Chris Hughes I guess you did Cayley somewhere, right?

view this post on Zulip Chris Hughes (Apr 23 2019 at 19:14):

No.

view this post on Zulip Chris Hughes (Apr 23 2019 at 19:14):

But it won't be hard.

view this post on Zulip Johan Commelin (Apr 23 2019 at 19:14):

@Greg Conneen It would be a very nice project to start with!

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:14):

Okay. I assume it won't be. That sounds like a great thing to do.

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:15):

I'm going to need help understanding data.equiv.basic though

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:17):

It looks like α ≃ β means α is isomorphic to β, given the defn. perm α makes sense. I'm still not completely comfortable with set theory notation and techniques in Lean, since I was introduced almost exclusively through propositions

view this post on Zulip Johan Commelin (Apr 23 2019 at 19:21):

@Greg Conneen Do you have an idea how you would formalise the statement?

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:23):

I'm looking into that now. The proof is trivial to me on paper. I should be fine in abstracting it. I'll definitely ask for help with it when I need it

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:28):

It looks like α ≃ β means α is isomorphic to β

This is an extremely confusing notation, but you'll get used to it

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:29):

The first piece of truth is α ≃ β is the type of isomorphisms from α to β

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:29):

So it's not a Prop, it contains data

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:29):

oh no

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:30):

lol that's certainly unintuitive

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:30):

The next layer of confusion is that an isomorphism from α to β is not only a map from α to β which happens to be an isomorphism, it's a bundle containing such a map, the corresponding inverse map and two proofs

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:31):

you need to read https://github.com/leanprover-community/mathlib/blob/master/src/data/equiv/basic.lean

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:31):

keeping the above explanation in mind

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:32):

That's perfectly fine. I can understand that such a map needs more info packaged in with it. So, what's the actual prop that A is iso to B?

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:32):

don't forget to first read back the section on coercions in TPIL

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:32):

And yeah I've been reading that file

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:33):

nonempty (α ≃ β)

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:33):

This is the Prop you are looking for

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:35):

Probably I missed that piece of information: at what stage of your math studies are you? (Knowing this will help choosing explanations for you)

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:38):

I don't think I've fully elaborated. I'm a 2nd year undergraduate math major currently taking my first semester of graduate real and complex analysis, and my third semester of graduate algebra. I plan on studying algebraic combinatorics, algebraic geometry, or algebraic topology. Either way, interested in algebra

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:40):

I'm afraid my knowledge of the American university system is clearly not good enough to understand that answer. Can you give a couple of examples of theorems you recently learned in your most advanced courses?

view this post on Zulip Kevin Buzzard (Apr 23 2019 at 19:42):

nonempty (α ≃ β)

That just says alpha bijects with beta. You want an isomorphism of what structure?

view this post on Zulip Johan Commelin (Apr 23 2019 at 19:43):

He doesn't need more structure. He is trying to formalise Cayley's theorem.

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:48):

Yeah. I'm currently in a course on wedderburn theory/commutative algebra. So, for example, we just covered the classification theorem for semisimple rings and semisimple algebras. In manifolds, we just covered the generalisation of stokes' theorem, and we just had an ending seminar on the Poincare lemma and the DeRham cohomology.

view this post on Zulip Patrick Massot (Apr 23 2019 at 19:49):

Thanks, this I understand (but I have no idea how to relate this to your abstract answer)

view this post on Zulip Greg Conneen (Apr 23 2019 at 19:50):

Well, I'm glad I could clarify for you

view this post on Zulip Kevin Kappelmann (Apr 26 2019 at 10:27):

What is the recommended/most elegant way to simplify/rewrite a hypothesis/assumption while re-stating the desired outcome of the simplification/rewriting? For example, doing

example (hyp : true  true = false) : false :=
have hyp : true = false, by { simp at hyp, assumption },
sorry

is not quite perfect as I have to write by { simp at hyp, assumption } (preferably, I'd like to simply write by simp at hyp) and leaves me with two hypotheses called hyp, namely

hyp : true  true = false,
hyp : true = false

Is there something like change for hypotheses?

view this post on Zulip Johan Commelin (Apr 26 2019 at 10:59):

There is rwa and simpa. Do those help you?

view this post on Zulip Kevin Kappelmann (Apr 26 2019 at 11:01):

Alright, that solves the former issue. Can I also somehow drop the non-simplified version from the list of assumptions?

view this post on Zulip Johan Commelin (Apr 26 2019 at 11:03):

@Kevin Kappelmann replace hyp : bla, by foobar?

view this post on Zulip Kevin Kappelmann (Apr 26 2019 at 11:08):

Yeah, that's exactly what I was looking for! thanks :) I do not think replace is mentioned in the tutorial. Is there some sort of document/website with "advanced tactics/APIs" that I can consult in such cases?

view this post on Zulip Johan Commelin (Apr 26 2019 at 11:09):

Which tutorial?

view this post on Zulip Johan Commelin (Apr 26 2019 at 11:09):

See the docs/ folder in mathlib. There is some stuff there.

view this post on Zulip Kevin Kappelmann (Apr 26 2019 at 11:10):

This document: https://leanprover.github.io/theorem_proving_in_lean/theorem_proving_in_lean.pdf

view this post on Zulip Patrick Massot (Apr 26 2019 at 11:38):

Is there something like change for hypotheses?

Yes, it's called change

view this post on Zulip Patrick Massot (Apr 26 2019 at 11:39):

If you have hyp : 1 + 1 = 2 you can change 2 = 2 at hyp

view this post on Zulip Kevin Kappelmann (Apr 29 2019 at 12:20):

It's me again :') I'm having some problems when using let-expressions + cases/induction. For example, this does not work

example (n m : ) : n + m = m + n :=
begin
let s := n + m,
induction n,
case nat.zero : {sorry}, -- error: could not find open goal of given case
case nat.succ : {sorry}
end

whereas this works

example (n m : ) : n + m = m + n :=
begin
induction n,
case nat.zero : {sorry},
case nat.succ : {sorry}
end

Does someone know what I am doing wrong?

view this post on Zulip Kevin Buzzard (Apr 29 2019 at 12:24):

Maybe that's a bug in case? You know that you don't need it, right?

example (n m : ) : n + m = m + n :=
begin
let s := n + m,
induction n,
{sorry},
{sorry}
end

view this post on Zulip Kevin Kappelmann (Apr 29 2019 at 12:25):

Yep, I'd really like to keep the case nat.xxx annotations though to keep my proofs more readable.

view this post on Zulip Kevin Buzzard (Apr 29 2019 at 12:25):

Make it a comment within the {}. And complain to the devs :-)

view this post on Zulip Kevin Kappelmann (Apr 29 2019 at 12:27):

Haha, alright :D Thanks

view this post on Zulip Kevin Buzzard (Apr 29 2019 at 12:29):

@Simon Hudon is this a bug?

view this post on Zulip Simon Hudon (Apr 29 2019 at 12:35):

I think it is. I'll look into it

view this post on Zulip Greg Conneen (Apr 30 2019 at 02:51):

Does unfold actually do anything other than change what the goal looks like? Isn't #print or Ctrl-click on what you're unfolding a replacement, since it's just a method of getting information about your goal? It seems that any proof can have the unfold statement removed, and it works just the same

view this post on Zulip Mario Carneiro (Apr 30 2019 at 03:01):

yes and no (and no). unfold will rewrite with equations that are not necessarily definitional equalities, so it might do more than just change the appearance of the goal. It's really a wrapper around simp with particular config options. dunfold is closer to your description, as it only does defeq simplifications. But there are two reasons that it's still not correct to say that it "doesn't actually do anything other than change what the goal looks like" and "any proof can have the dunfold statement removed and it works just the same". First, it does actually do something - it inserts an id term into the result (the partial proof being constructed). So you can see the result of dsimp and dunfold applications in the resulting proof if you #print it. This is done to keep typechecking time down by remembering the simplification path in the proof term.

The more important reason why dunfold and friends can't necessarily be removed from a proof is because many tactics depend on the syntactic shape of the goal or a hypothesis. For example, rw will not match against the goal if some definitional unfolding is required to see the constant that appears. For example if the goal is 2 * n = 0 where n : nat, then this is defeq to n + n = 0 but rw add_comm would only work on the second form of the goal. So anything that "changes what the goal looks like" could potentially affect whether a later tactic succeeds. That said, many tactics don't care about anything beyond defeq, in particular apply, refine and exact, and in many cases you can remove superfluous unfold and dunfold tactics without breaking the proof.

view this post on Zulip Simon Hudon (May 03 2019 at 21:45):

@Kevin Kappelmann I now have a fix for your let / case issue. It should be in the next nightly build of Lean 3.5.0c

view this post on Zulip Greg Conneen (May 04 2019 at 20:07):

Real quick, what is a meta variable and why is tactic.finish absolutely packed with them? I'm not sure exactly what's going on, but it seems that any trivial propositional technique is proven immediately with by finish

view this post on Zulip Patrick Massot (May 04 2019 at 20:08):

What do you mean finish is packed with metavariable?

view this post on Zulip Patrick Massot (May 04 2019 at 20:09):

A meta-variable is a kind of hole Lean will have to fill in. It can be the goal you need to solve or some implicit argument to be inferred by unification

view this post on Zulip Greg Conneen (May 04 2019 at 20:13):

I just mean that when I pressed Ctrl-Click on tactic.finish, I came upon a file that was filled with the keyword meta and I wasn't sure what any of it meant

view this post on Zulip Patrick Massot (May 04 2019 at 20:14):

oohh

view this post on Zulip Patrick Massot (May 04 2019 at 20:14):

that's a different meta

view this post on Zulip Greg Conneen (May 04 2019 at 20:15):

I suppose so, I just assumed that meta def was defining a metavariable, although I suppose that wouldn't make sense given my preconceived notion of what a metavariable is

view this post on Zulip Patrick Massot (May 04 2019 at 20:15):

meta in this context means "unsafe". It's code that won't be checked by Lean. It particular it doesn't have to be provably terminating

view this post on Zulip Greg Conneen (May 04 2019 at 20:15):

Why would one ever need such a thing?

view this post on Zulip Patrick Massot (May 04 2019 at 20:15):

Typically tactics (the commands you type between begin and end) are meta. They produce proofs that will be checked by Lean. But the way they produces those proofs is freestyle

view this post on Zulip Greg Conneen (May 04 2019 at 20:17):

Ah, okay. So it's not just a cheeky way of making axioms. So the reason I can solve so many things with by finish is because all of the structures in finish are using this meta keyword? I assume without it, there wouldn't be a way of taking arbitrary propositions and figuring out how to solve them

view this post on Zulip Greg Conneen (May 04 2019 at 20:18):

That is, finish wouldn't know how to solve a proposition handed to it if it weren't in a specific order of some sort

view this post on Zulip Scott Morrison (May 04 2019 at 20:18):

meta code can do non-terminating recursion, and it can also work with "reflected" versions of mathematical objects, i.e. their actual representations as expr objects in the C++ code.

view this post on Zulip Patrick Massot (May 04 2019 at 20:18):

finish constructs a proof for you

view this post on Zulip Greg Conneen (May 04 2019 at 20:19):

Okay, that's really cool @Scott Morrison

view this post on Zulip Patrick Massot (May 04 2019 at 20:19):

I don't think there is any risk of non-termination here. But the type of Lean expressions is meta, for reasons too long to explain (unless you understand what Scott wrote)

view this post on Zulip Scott Morrison (May 04 2019 at 20:20):

This is one of the lovely things about Lean --- you can write new tactics (i.e. programs that construct proofs, but aren't necessarily themselves correct) in Lean itself.

view this post on Zulip Greg Conneen (May 04 2019 at 20:20):

I understand C++ enough to generally know what he means

view this post on Zulip Scott Morrison (May 04 2019 at 20:20):

In previous interactive theorem provers you needed to step out, either into the base implementation language, or some DSL, to write new tactics.

view this post on Zulip Greg Conneen (May 04 2019 at 20:21):

So, even with meta, there's still no way to prove false? Because a bad tactic won't construct a good proof?

view this post on Zulip Greg Conneen (May 04 2019 at 20:21):

That makes sense

view this post on Zulip Scott Morrison (May 04 2019 at 20:21):

The meta keyword protects the real maths from these "helper" functions that we write to help construct proofs.

view this post on Zulip Greg Conneen (May 04 2019 at 20:21):

ahh

view this post on Zulip Scott Morrison (May 04 2019 at 20:22):

Exactly. The tactic framework lets you run meta code to produce proof terms, but those proof terms will be rejected if they refer to any meta functions.

view this post on Zulip Greg Conneen (May 04 2019 at 20:22):

so, how would a noob go about using meta? Or, should I just not even touch the thing?

view this post on Zulip Patrick Massot (May 04 2019 at 20:23):

It depends on your taste, background and goals

view this post on Zulip Scott Morrison (May 04 2019 at 20:23):

Read https://github.com/leanprover-community/mathlib/blob/master/docs/extras/tactic_writing.md

view this post on Zulip Scott Morrison (May 04 2019 at 20:23):

And start reading all the files in src/tactic/ in the mathlib repository.

view this post on Zulip Scott Morrison (May 04 2019 at 20:23):

and ask here :-)

view this post on Zulip Patrick Massot (May 04 2019 at 20:23):

Yes, reading that tutorial will give you a first glance at what it looks like

view this post on Zulip Patrick Massot (May 04 2019 at 20:24):

Reading src/tactic/ will give you a lot more (after a lot more time)

view this post on Zulip Greg Conneen (May 04 2019 at 20:24):

Great, thank you. My goal generally is to git gud in Lean, but eventually I want to start implementing some actual maths. I expect that will take me some time, given I'll have to read quite a bit of mathlib

view this post on Zulip Patrick Massot (May 04 2019 at 20:25):

You don't have to read all of mathlib before starting to implement actual maths

view this post on Zulip Greg Conneen (May 04 2019 at 20:28):

sure, but I'd like to understand a chunk of what's already there on a fundamental level

view this post on Zulip Scott Morrison (May 04 2019 at 20:28):

Do you have an idea what maths you'd like to do?

view this post on Zulip Scott Morrison (May 04 2019 at 20:29):

If you're ever tempted to add documentation to stuff you're reading, documentation-only pull requests are very welcome. :-)

view this post on Zulip Greg Conneen (May 04 2019 at 20:29):

I'd like to define a manifold, and maybe prove the inverse/implicit function theorem

view this post on Zulip Greg Conneen (May 04 2019 at 20:30):

I just really need to look over how topology and euclidean space are implemented first

view this post on Zulip Greg Conneen (May 04 2019 at 20:30):

Also, do we have the definition of a metric space?

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:32):

@Greg Conneen If you want to implement some actual maths in Lean, then don't try to get good at Lean first, just try to implement some actual maths in Lean, get stuck, ask for help here, and you will succeed.

view this post on Zulip Sebastien Gouezel (May 04 2019 at 20:32):

I am precisely working on the definition of a manifold. Work in progress (very much in a preliminary state) at https://github.com/sgouezel/mathlib/blob/aa7fbab39d1e6a01665e24e6197b09338e855467/src/geometry/manifolds/basic.lean#L1598

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:32):

I have no idea how to write tactics. Tactics are written in meta code because they can fail. You don't need to know anything about tactic-writing (which is what people use meta code for) to write maths.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:33):

However, what you do need to know is what is already there and what is being worked on, because this changes fast here

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:34):

Yes we have metric spaces. You can see this yourself by firing up a project with mathlib as a dependency in VS Code and searching for metric space. This is a really important beginner skill to learn.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:35):

Make sure that "the cog doesn't have a box around it" in "files to exclude" in VS Code. That way you can search your dependencies.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:35):

Several people would like to define manifolds and people are sort of in the middle of things, so it might not be a perfect project right now for a beginner.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:36):

Definitions are harder than theorems; proofs can be sloppy but it's important to get definitions right.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:36):

One big obstruction to doing much with manifolds is that we don't have enough calculus, but again people are working on this and things are changing fast.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:37):

Bump functions are still a little out of reach at the minute, but it won't be long until we have them.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:38):

For polynomials we have multivariable ones and single variable ones; I am not an expert in either analysis or Lean-analysis, but I am wondering whether we are going to need a robust theory of calculus in one real variable, proving basic theorems such that the derivative of the integral is the function. I don't think we even have that.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:39):

We have no complex analysis worth mentioning, not even integrating along a reasonable path.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:40):

Because of our lack of analysis, this makes manifolds harder to do, however having goals like manifolds in mind is driving the library forwards in the right direction (as far as I am concerned). Lean seems to me to be focussing on the kind of mathematics mathematicians do, as opposed to the kind of mathematics that computer scientists have managed to pick up somehow.

view this post on Zulip Greg Conneen (May 04 2019 at 20:43):

Gotcha, thanks for the information. Do you think that complex would be a good thing to get working on, or do we not have it because it's hard to implement?

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:49):

I am not an analyst and it's been nearly 30 years since I thought about the basics, Cauchy's integral formula etc. I've never taught the course either, so I am not the person to ask.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:50):

One thing I know was an issue is that someone has to make a decision about in what generality to define path integrals -- C^infinity paths isn't good enough because you want to integrate round semicircles and rectangles etc.

view this post on Zulip Kevin Buzzard (May 04 2019 at 20:51):

I really don't know what's there already though; I know a lot of the algebra stuff in Lean but the analysis stuff is changing quickly at the minute.

view this post on Zulip Patrick Massot (May 04 2019 at 20:56):

Kevin, the way this is going, we'll soon have manifolds with boundary and corners. When we'll have differential forms this will be much more than enough for rectangle and semi-circles

view this post on Zulip Kevin Buzzard (May 04 2019 at 21:17):

Woo hoo we'll have de Rham. cohomology one day. Is this in any other theorem prover?

view this post on Zulip Wojciech Nawrocki (Jun 10 2019 at 12:24):

Is it possible to "unimport" core/prelude, i.e. the basic definitions of nat, eq, etc, leaving an environment pretty much free of any definitions?

view this post on Zulip Kevin Buzzard (Jun 10 2019 at 12:25):

You can put prelude at the top of your file

view this post on Zulip Kevin Buzzard (Jun 10 2019 at 12:25):

which translates to "this file is part of the prelude" (so don't be importing all the prelude)

view this post on Zulip Kevin Buzzard (Jun 10 2019 at 12:25):

I've never used it, I've just seen people suggest it

view this post on Zulip Wojciech Nawrocki (Jun 10 2019 at 12:26):

Yup, that seems to work. Thank you!

view this post on Zulip Wojciech Nawrocki (Jun 11 2019 at 22:56):

Is the notation h.fn arg given class myclass (α: Type*) := (fn: α → ℕ) and [h: myclass α] discouraged? It stops working for example if fn: ℕ → α because the type argument α to myclass.fn becomes explicit, i.e. myclass.fn : Π (α : Type u_1) [c : myclass α], ℕ → α.

view this post on Zulip Adrian Chu (Jun 19 2019 at 15:44):

Given a positive integer n, how to define a vector with n entries? Thanks

view this post on Zulip Kenny Lau (Jun 19 2019 at 15:45):

vector \alpha n

view this post on Zulip Adrian Chu (Jun 19 2019 at 15:46):

Oh, and say x is the vector, how do we decribe its i-th entry?

view this post on Zulip Kenny Lau (Jun 19 2019 at 15:46):

import data.vector
universes u
variables (α : Type u) (n : )
#check vector α n

view this post on Zulip Kenny Lau (Jun 19 2019 at 15:47):

import data.vector
universes u
variables (α : Type u) (n : ) (v : vector α n) (k : fin n)
#check v.nth k

view this post on Zulip Adrian Chu (Jun 19 2019 at 15:55):

how to do summation from i=1 to n ?

view this post on Zulip Kenny Lau (Jun 19 2019 at 16:00):

import data.vector2
universes u
variables (α : Type u) [has_zero α] [has_add α] (n : ) (v : vector α n)
#check v.to_list.sum

view this post on Zulip Adrian Chu (Jun 19 2019 at 16:18):

one more question: how do we define new 3-vector, say, (x,y,x+y) where x, y are variable?

view this post on Zulip Adrian Chu (Jun 19 2019 at 16:20):

and more importantly, is there some online resource where I can read and get familiarized with these simple commands? I skimmed through theorem_proving_in_lean.pdf and couldn't find what I want... I feel like i'm asking too many noob questions like an idiot lol

view this post on Zulip Kenny Lau (Jun 19 2019 at 16:23):

import data.vector
universes u
variables (α : Type u) [has_add α] (x y : α)
#check ([x, y, x+y], rfl : vector α 3)

view this post on Zulip Adrian Chu (Jun 19 2019 at 16:25):

how about an n-vector like (x, 2x, 3x, ..., nx)? :mischievous:

view this post on Zulip Bryan Gin-ge Chen (Jun 19 2019 at 16:25):

is there some online resource where I can read and get familiarized with these simple commands

Unfortunately there isn't much beyond TPiL. You'll have to get used to reading source files. Here's data.vector.

view this post on Zulip Adrian Chu (Jun 19 2019 at 16:26):

is there some online resource where I can read and get familiarized with these simple commands

Unfortunately there isn't much beyond TPiL. You'll have to get used to reading source files. Here's data.vector.

Oh i see, thanks

view this post on Zulip Floris van Doorn (Jun 19 2019 at 16:28):

Currently, if you want to figure these things out yourself, the best way is just to look through the library files in mathlib (and core). You can go to data/vector2 in mathlib or the file Bryan mentioned in core. Also, operations on list might be useful to know for vectors. Other ways to find things you're searching for:

view this post on Zulip Floris van Doorn (Jun 19 2019 at 16:29):

(x, 2x, 3x, ..., nx)

without looking at the library: hopefully vector.range and vector.map both exists, from which you should be able to figure it out (if not, use list.range and/or list.map)

view this post on Zulip Kenny Lau (Jun 19 2019 at 16:35):

how about an n-vector like (x, 2x, 3x, ..., nx)? :mischievous:

import algebra.group_power data.pnat data.vector
universes u
variables {α : Type u} [has_add α]
def multiple (x : α) :   α
| 0 := x -- junk value
| 1 := x
| (n+2) := multiple (n+1) + x
variables (x : α) (n : )
#check ((list.range n).map (λ i, multiple x (i+1)), by simp : vector α n)

view this post on Zulip Floris van Doorn (Jun 19 2019 at 16:43):

If \a is an add_monoid, you can use add_monoid.smul instead of multiple

view this post on Zulip Adrian Chu (Jun 19 2019 at 17:00):

import data.vector2
universes u
variables (α : Type u) [has_zero α] [has_add α] (n : ) (v : vector α n)
#check v.to_list.sum

Is there a way to do summation without using vector?

view this post on Zulip Johan Commelin (Jun 19 2019 at 17:02):

You might be interested in finset.sum and finset.range. The first gives you sums, the second gives you the finset "{0, ..., n-1}"

view this post on Zulip Kevin Buzzard (Jun 19 2019 at 17:04):

@Adrian Chu the problem is that TPIL just deals with core Lean, and you are asking about how to use stuff in the maths library. When I was learning the basics, I found the maths library very intimidating, but when I realised that I should just stop reading the proofs and instead just look at the definitions, I found that I could proceed with my mathematics very nicely, which in turn led to more understanding, which in turn made reading the proofs which I had been ignoring all this time much easier.

One thing I learnt fairly quickly was to abstract exactly what I wanted. For example you asked how to make (x, 2x, 3x, ..., nx). But in fact you can break this down into smaller questions. Probably you know well how to make a function like lam n, (n + 1) * x, so then you realise that what you really need is how to make (f 0, f 1, ..., f m). Now from general functional programming you might know that they like things like working out how to take a function f and to apply it to a vector like (0 1 2 ... n) so now you have two smaller questions -- how to make a vector like (0 1 2 ... n) and how to apply a function to every element of a vector. By this stage we are in the world where these ideas have a common name -- range for (0 1 2 ... n) and map for applying a function to a bunch of things at once. Now you can begin to guess the actual names of the functions you want.

Learning to think this way was a very important stepping stone for me; I slowly began to realise that I was developing a method for being able to answer my own questions of this nature. I am still learning, but this is the way to think about it. For every question, figure out how to build it from general tools and then figure out where those general tools are, perhaps by figuring out first what they should be called.

view this post on Zulip Adrian Chu (Jun 19 2019 at 17:16):

I see... I feel that TPiL is like a book teaching grammar, while mathlib is a dictionary. And knowing all the grammar does not immediately guarantee one can fluently read a dictionary, let alone writing sentences or paragraphs.

view this post on Zulip Kevin Buzzard (Jun 19 2019 at 19:27):

If you look through something like data.list.basic and take a look at just the names and the statements of the theorems, you can learn a lot about mathlib's naming conventions. The description above (breaking what you want down into small pieces) is I think how you're supposed to think about functional programming; the same sort of themes come up again and again; import data.finset and then use #check to look at the types of list.map and multiset.map and finset.map and it slowly dawns on you that map means a very specific thing in this game. Then try list.range and multiset.range and finset.range. It will slowly dawn on you by people are suggesting that you use vector.map and vector.range without even knowing if these functions are defined in Lean -- and if they're not then it's not hard to make them.

view this post on Zulip Luis Berlioz (Jun 20 2019 at 04:08):

Can I place a variable declaration in the middle of a proof?
For example instead of this:

variable s : α
example : r  (  x : α, r) :=
assume hr : r,
show (  x : α, r), from   s, hr 

I want the variable s : α declared inside the proof, like:

example : r  (  x : α, r) :=
assume hr : r,
variable s : α
show (  x : α, r), from   s, hr 

view this post on Zulip Johan Commelin (Jun 20 2019 at 04:10):

No, that's not possible. Maybe you mean have or let?

view this post on Zulip Johan Commelin (Jun 20 2019 at 04:11):

The goal is to prove that some alpha exists. You can't just grab it out of nowhere.

view this post on Zulip Luis Berlioz (Jun 20 2019 at 04:13):

Ok, that makes sense.

view this post on Zulip Adrian Chu (Jun 20 2019 at 10:14):

how to fix
def y := [1,2,3] #eval 4+y.nth 2 ? why can't I add?

view this post on Zulip Mario Carneiro (Jun 20 2019 at 10:16):

nth returns option nat

view this post on Zulip Mario Carneiro (Jun 20 2019 at 10:17):

you should be able to use y.nth_le 2 dec_trivial

view this post on Zulip Adrian Chu (Jun 20 2019 at 10:25):

oh it works, thanks! but what do .nth_le and dec_trivial means?

view this post on Zulip Mario Carneiro (Jun 20 2019 at 10:26):

no one wants an array out of bounds exception

view this post on Zulip Mario Carneiro (Jun 20 2019 at 10:26):

the dec_trivial is a proof that 2 < 3

view this post on Zulip Adrian Chu (Jun 20 2019 at 10:32):

i see

view this post on Zulip Adrian Chu (Jun 20 2019 at 10:52):

How about

def y := [1,2,3]
def g (i : fin 3) : ℕ := y.nth_le i-1
def f (i : fin 3) : ℕ := 4 + y.nth_le i-1 dec_trivial

? What's wrong?

view this post on Zulip Reid Barton (Jun 20 2019 at 11:42):

Clearly you intended to have parentheses around i-1, but I'm not sure what you are trying to achieve

view this post on Zulip Wojciech Nawrocki (Jun 20 2019 at 11:45):

Yep, function application binds tighter than subtraction, so to express what you want you need to put parentheses around i-1. You're also missing a proof that (i-i < list.length y) in g (no second argument is given).

view this post on Zulip Adrian Chu (Jun 20 2019 at 12:03):

Yep, function application binds tighter than subtraction, so to express what you want you need to put parentheses around i-1. You're also missing a proof that (i-i < list.length y) in g (no second argument is given).

How exactly should I give the proof then?

view this post on Zulip Mario Carneiro (Jun 20 2019 at 12:04):

You could use fin.last instead

view this post on Zulip Mario Carneiro (Jun 20 2019 at 12:06):

If you were doing this from scratch, you would be proving i-1 < 3 given i < 3. There are theorems in data.nat.basic to help with this

view this post on Zulip Mario Carneiro (Jun 20 2019 at 12:06):

alternatively, you can skip the proof and just handle the possibility of error using nth

view this post on Zulip Wojciech Nawrocki (Jun 20 2019 at 12:14):

I'm kinda surprised that forall (n m k: nat), n < m -> n-k < m isn't already in mathlib.

view this post on Zulip Mario Carneiro (Jun 20 2019 at 12:36):

it's just the composition of lt_of_le_of_lt and sub_le

view this post on Zulip Scott Morrison (Jun 20 2019 at 22:45):

That said, I think we should add it. Finding these lemmas is excruciating for beginners (who haven't even learnt that you can in principle guess the names of most basic facts, let alone learnt how to do it).

view this post on Zulip Scott Morrison (Jun 20 2019 at 22:47):

How bad is the downside of swamping Lean with these sort of "composition of two lemmas" lemmas?

view this post on Zulip Mario Carneiro (Jun 20 2019 at 22:47):

there is a combinatorial explosion

view this post on Zulip Mario Carneiro (Jun 20 2019 at 22:48):

it's not even clear which compositions are the most common

view this post on Zulip Mario Carneiro (Jun 20 2019 at 22:48):

and we don't even have the complete set of basic lemmas

view this post on Zulip Mario Carneiro (Jun 20 2019 at 22:49):

I would rather put more smarts into library_searchtype provers than flood the library with random facts

view this post on Zulip Scott Morrison (Jun 20 2019 at 23:27):

/me needs to get back to back

view this post on Zulip Tim Daly (Jun 21 2019 at 00:35):

There need not be a combinatorial explosion, nor does the naming convention have to be so baroque.

It appears to me that Lean is using a flat namespace. The naming convention makes it really hard to guess what you need.

Farmer and Carette (McMaster U.) have the notion of "tiny theories" which intrioduce a single axiom or a single signature. These can be combined to form larger objects which inherit the axioms and signatures. So, for instance, there would be a "commutative" axiom which can be inherited everywhere it makes sense.

This hierarchical organization enables re-use of axioms and signatures and allows the same name to occur in different paths in the inheritance graph.

view this post on Zulip Mario Carneiro (Jun 21 2019 at 00:37):

Lean has namespaces, which are used to label the major components in the theorem, or the broad area in which it lives

view this post on Zulip Mario Carneiro (Jun 21 2019 at 00:39):

The naming convention is designed to be easy to guess based on the statement, so you can think of a statement that you think is true and then search for the corresponding name. I'm curious how you would propose to improve on that scheme

view this post on Zulip Mario Carneiro (Jun 21 2019 at 00:41):

The number of theorems does increase exponentially as the depth increases. If there are n theorems, then there are O(n^2) ways to compose two of them, O(n^3) ways to compose three, and so on. Even 2n theorems is a major increase; n^2 is totally intractable

view this post on Zulip Tim Daly (Jun 21 2019 at 00:44):

Namespaces don't implement an inheritance graph in any generality. You'd like to state the commutative axiom in one place in the graph and have it available whereever it is used. What you really want is genreal "name polymorphism" so that the name 'factor' can have different semantics in different contexts. Using 'dotted namespace notation' forces the user to manage the namespace. This doesn't scale.

view this post on Zulip Scott Morrison (Jun 21 2019 at 00:45):

Well... only a fraction of those n^2 theorems actually make sense. I wish I had a better sense of what that fraction was. I guess this could be automated. :-)

view this post on Zulip Scott Morrison (Jun 21 2019 at 00:45):

@Tim Daly, of course Lean does state the commutative axiom only once.

view this post on Zulip Scott Morrison (Jun 21 2019 at 00:46):

(Okay, twice, once for "additive" structures and once for "multiplicative", which is lame, but still, it's only 2. :-)

view this post on Zulip Tim Daly (Jun 21 2019 at 00:58):

How does Lean handle a Lie algebra? Lie groups are skew-symmetric and they are non-associative. So

x*y = -y * x and

x * (y * z) = (x * y) * z + y * (x * z)

Do you have to "built it from nothing" using an odd naming convention for things like "algebra.lie.cross_product_skew_symmetric."?

Axiom, which uses something similar to Farmer/Carette "tiny theories" has 10,000 functions but a much smaller set of names.

view this post on Zulip Scott Morrison (Jun 21 2019 at 01:01):

As far as I'm aware no one has done anything on Lie algebras yet.

view this post on Zulip Mario Carneiro (Jun 21 2019 at 01:08):

We would normally use some naming convention based on the symbols in the axiom, but for core laws that have names we have a small set of name segments to describe the law. We've not dealt with these laws before, so I guess they would require a new terminology; I would use something like lie_algebra.mul_anticomm and lie_algebra.jacobi for these

view this post on Zulip Mario Carneiro (Jun 21 2019 at 01:10):

You should take a look at https://github.com/leanprover-community/mathlib/blob/master/docs/contribute/naming.md

view this post on Zulip Scott Morrison (Jun 21 2019 at 01:10):

I wonder, actually, if we'd even want to use mul for a Lie algebra. It's true that it distributes over addition just as a "normal" multiplication does, but otherwise has little in common.

view this post on Zulip Tim Daly (Jun 21 2019 at 01:23):

This places the burden of finding multiplication in an algebra on the user's ability to infer names. Polymorphic names could be disambiguated by a prolog-like match algorithm. The naming convention "is what it is", of course. But it seems to me that I have to read the original sources and "internalize" the names in my mind, which is a very small place.

view this post on Zulip Mario Carneiro (Jun 21 2019 at 01:24):

I'm not sure what problem you are trying to solve. There are multiple theorems with the same name in different namespaces, and we take care to have them be the same or clearly analogous

view this post on Zulip Mario Carneiro (Jun 21 2019 at 01:26):

If you have multiple theorems with the same name in scope (because you have opened multiple namespaces), it will disambiguate them based on the type

view this post on Zulip Andrew Ashworth (Jun 21 2019 at 01:29):

isn't this tiny theory system the type class inference system in disguise?

view this post on Zulip Tim Daly (Jun 21 2019 at 01:29):

Namespaces are a kind of type in that case. If they were all "in scope" then there is no need for namespaces?

view this post on Zulip Andrew Ashworth (Jun 21 2019 at 01:30):

specifically the often linked "unbundled type classes" section here: https://github.com/leanprover/lean/wiki/Refactoring-structures

view this post on Zulip Mario Carneiro (Jun 21 2019 at 01:30):

well no, namespaces are separate from types. The type system is DTT, the namespace system is just names and overloading

view this post on Zulip Tim Daly (Jun 21 2019 at 01:30):

Disguise? It is the type class inference problem.

view this post on Zulip Tim Daly (Jun 21 2019 at 01:31):

I admit ignorance of the full details. Further study on my part is needed.

view this post on Zulip Mario Carneiro (Jun 21 2019 at 01:32):

You can always refer to a theorem by its full name if the file that defines it has been imported. Opening a namespace just makes the name a bit shorter to reference

view this post on Zulip Adrian Chu (Jun 21 2019 at 03:35):

Btw, when Lean 4 comes out one day, what will happen to mathlib?

view this post on Zulip Mario Carneiro (Jun 21 2019 at 03:48):

Lean 4 is already "out", but not production ready. When it is solid we will start working on a port

view this post on Zulip Mario Carneiro (Jun 21 2019 at 03:49):

there isn't much point working on it at scale yet because it's too unstable and unfinished, although testing out a single file might be worthwhile

view this post on Zulip Adrian Chu (Jun 21 2019 at 03:52):

I see, then when it's stable enough, how much manual work is needed to update mathlib?

view this post on Zulip Bryan Gin-ge Chen (Jun 21 2019 at 03:53):

(deleted)

view this post on Zulip Mario Carneiro (Jun 21 2019 at 03:53):

somewhere between "a significant endeavor" and "a total overhaul"

view this post on Zulip Mario Carneiro (Jun 21 2019 at 03:54):

If we can get any refactoring tools in lean 3.5c then it may make this a lot easier. There is a lot of silly busywork like changing the naming convention

view this post on Zulip Adrian Chu (Jun 21 2019 at 09:12):

variable n : ℕ
def vec_exp1 (i : fin n) (x : vector ℕ n) (y : vector ℕ n) : ℕ :=
    (x.nth i)^(y.nth i)
def vec_exp2 (x : vector ℕ n) (y : vector ℕ n) : vector ℕ n :=
    ⟨(list.range n).map (λ i, vec_exp1 i x y), by simp⟩

view this post on Zulip Adrian Chu (Jun 21 2019 at 09:13):

I am trying to compute the entry-wise exponential of two n-vector. but the last line has error: the term x has type vector N n but is expected to have type fin i. what is wrong??

view this post on Zulip Adrian Chu (Jun 21 2019 at 09:14):

btw if i change n to 3, it works

view this post on Zulip Mario Carneiro (Jun 21 2019 at 09:17):

the variable n : N is getting added to vec_exp1, so it actually takes four arguments

view this post on Zulip Mario Carneiro (Jun 21 2019 at 09:17):

you should make it implicit by writing it in braces

view this post on Zulip Adrian Chu (Jun 21 2019 at 09:24):

ah i see! but now I'm getting another error in the last line: vec_exp1 i, the term i has type \N but is expected to have type fin ?m_1. how can I fix it?

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 09:48):

If you hover over vec_exp1 you can see it has type vec_exp1 : Π {n : ℕ}, fin n → vector ℕ n → vector ℕ n → ℕ. So it wants an input of type fin n and an input of type vector ℕ n. If you hover over i you see it has type . So now you can understand the error. How to fix it -- make the types correct ;-) Do you have a more specific question?

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 09:54):

Do you understand how to interpret (list.range n).map? Hover over list.range to see it has type ℕ → list ℕ. So list.range n has type list ℕ. Now this clever l.map thing means list.map l and doing #check list.map you can see the type of that too. You can just unravel everything. Your code doesn't work because when you unravel it it doesn't make sense.

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 09:57):

Figuring out yourself what you want to do and then the types of the functions you want which will do them is a really good exercise for Lean beginners. It gets you thinking in the "functional programming" way.

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 10:01):

I think you would be better off using vector.map than list.map because you're dealing with vectors. I see there is no vector.range though. It would be a good exercise to define vector.range first. Its type should be this:

def vector.range : Π (n : ℕ), vector ℕ n := sorry

view this post on Zulip Adrian Chu (Jun 21 2019 at 10:28):

If you hover over vec_exp1 you can see it has type vec_exp1 : Π {n : ℕ}, fin n → vector ℕ n → vector ℕ n → ℕ. So it wants an input of type fin n and an input of type vector ℕ n. If you hover over i you see it has type . So now you can understand the error. How to fix it -- make the types correct ;-) Do you have a more specific question?

yeah, i understand the error but just don't know what how to make i of type fin n. Should I use something like max i n? Also, why does #check max 3 4 works while #eval max 3 4 don't?

view this post on Zulip Adrian Chu (Jun 21 2019 at 10:29):

I think you would be better off using vector.map than list.map because you're dealing with vectors. I see there is no vector.range though. It would be a good exercise to define vector.range first. Its type should be this:

def vector.range : Π (n : ℕ), vector ℕ n := sorry

OK! i will try...

view this post on Zulip Johan Commelin (Jun 21 2019 at 10:35):

Actually... why do you want to work with vectors?

view this post on Zulip Johan Commelin (Jun 21 2019 at 10:35):

That's the annoying thing: you have to choose a data representation.

view this post on Zulip Johan Commelin (Jun 21 2019 at 10:35):

It could be list, or vector or maps from fin n.

view this post on Zulip Johan Commelin (Jun 21 2019 at 10:35):

Possibly other choices.

view this post on Zulip Johan Commelin (Jun 21 2019 at 10:36):

What is the end goal?

view this post on Zulip Johan Commelin (Jun 21 2019 at 10:36):

"Just goofing around" is a valid answer, in which case using vectors is totally fine.

view this post on Zulip Adrian Chu (Jun 21 2019 at 10:46):

What is the end goal?

The goal is simply to have an n-tuple of numbers. Now you mention it, fin n \to \N does sounds a lot more simplier. I will use this....

view this post on Zulip Johan Commelin (Jun 21 2019 at 11:11):

fin n → ℕ does sounds a lot more simplier.

Depends...

view this post on Zulip Johan Commelin (Jun 21 2019 at 11:11):

If you want to write down an explicit 5-tuple, I guess vector is easier.

view this post on Zulip Adrian Chu (Jun 21 2019 at 12:02):

fin n → ℕ does sounds a lot more simplier.

Depends...

say now i have f:fin n → ℕ and want to calculate f(1)+...+f(n). do I have to convert f to a vector and use .tolist_sum ? or is there a more direct way?

view this post on Zulip Alexander Bentkamp (Jun 21 2019 at 12:29):

Try finset.univ.sum.

view this post on Zulip Adrian Chu (Jun 21 2019 at 14:02):

i know that int.gcd can find the gcd of two numbers. how about finding the gcd of n numbers? what is the best way?

view this post on Zulip Marc Huisinga (Jun 21 2019 at 14:12):

since gcd is an associative function, you can foldr or foldl over the collection of numbers

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 14:59):

yeah, i understand the error but just don't know what how to make i of type fin n. Should I use something like max i n?

Do you understand how to make a term of type fin n? By definition, a term of type fin n is a pair, consisting of a natural number i and a proof that i < n. In your function you seem to have a random natural number i with no conditions at all, so it will be impossible to prove that i < n. That was why I was encouraging you to step back a bit and think about the functions you're using and what you're doing.

Also, why does #check max 3 4 works while #eval max 3 4 don't?

#eval max 3 4 works for me. Can you post a MWE?

view this post on Zulip Adrian Chu (Jun 21 2019 at 15:17):

What does MWE stand for? lol

view this post on Zulip Adrian Chu (Jun 21 2019 at 15:18):

And the error message for #eval max 3 4 is "code generation failed, VM does not have code for lattice.lattice.conditionally_complete_linear_order_bot'"

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 15:18):

Minimal working example. I type #eval max 3 4 and it worked fine. I was wondering exactly what you did. A MWE is something you can cut and paste so I can see the error you're seeing. Currently I can't do that becaue you're only posting the line which gave the error.

view this post on Zulip Adrian Chu (Jun 21 2019 at 15:27):

Oh, I figured it out. It is because I imported ring_theory.principal_ideal_domain

view this post on Zulip Adrian Chu (Jun 21 2019 at 16:49):

given positive integers a and b how can we prove that the sum of a b's is ab?

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 16:50):

How are you defining the sum of a b's? The devil is in the detail for this one.

view this post on Zulip Reid Barton (Jun 21 2019 at 16:50):

And why do you want to prove it?

view this post on Zulip Reid Barton (Jun 21 2019 at 16:53):

You might decide the definition of a * b already answers your question

view this post on Zulip Reid Barton (Jun 21 2019 at 16:53):

Or possibly b * a

view this post on Zulip Adrian Chu (Jun 21 2019 at 16:54):

How are you defining the sum of a b's? The devil is in the detail for this one.

@Kevin Buzzard I'm using finset.univ.sum (λ i : fin a, b)

view this post on Zulip Adrian Chu (Jun 21 2019 at 16:56):

And why do you want to prove it?

@Reid Barton
This is a crucial lemma in a theorem I wanna prove. Specifically, I need to prove that given positive integers b, c, the sum of b (b^c)'s is b^(c+1)

view this post on Zulip Reid Barton (Jun 21 2019 at 16:57):

Well this statement still has the phrase "the sum of x ys" in it so I could ask the same question again

view this post on Zulip Reid Barton (Jun 21 2019 at 16:59):

We all know the sum of X Ys is X * Y, so why not just formalize the statement using *

view this post on Zulip Adrian Chu (Jun 21 2019 at 16:59):

Well this statement still has the phrase "the sum of x ys" in it so I could ask the same question again

I need to show finset.univ.sum (λ i : fin a, b)=a*b

view this post on Zulip Reid Barton (Jun 21 2019 at 16:59):

OK, that's a statement that we should be able to prove

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:05):

I feel like this should be in the library. Is it sum_const or something? shrug

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:06):

@Adrian Chu I would be tempted to find where finset.sum is defined in mathlib (just right click on it in VS Code and go to the definition) and take a look at the next 50 lemmas after its definition, to see if there is anything useful there.

view this post on Zulip Adrian Chu (Jun 21 2019 at 17:08):

I found this

theorem sum_const (ι : Type u) (a : cardinal.{u}) : sum (λ _:ι, a) = mk ι * a :=
quotient.induction_on a $ λ α, by simp; exact
  quotient.sound equiv.sigma_equiv_prod _ _⟩

in set theory/cardinal

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:12):

That's the wrong kind of sum. This is exactly why the devil is in the detail.

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:14):

Was there nothing near finset.sum?

view this post on Zulip Adrian Chu (Jun 21 2019 at 17:21):

I can't see what I want (possibly due to my own ignorance)

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:24):

Ok I'll take a look.

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:24):

It is indeed finset.sum_const

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:25):

You could have just tried #check finset.sum_const

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:35):

Aah, I bet you didn't have the right import.

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:36):

import algebra.big_operators

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:36):

Yeah, I don't know how to search for it if you don't have the right import. It would be nice if it was easy just to import everything temporarily.

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 17:37):

Oh wait, but you need that import for finset.sum...

view this post on Zulip Kenny Lau (Jun 21 2019 at 17:52):

import algebra.big_operators data.fintype

example {a b : } : (finset.univ : finset $ fin a).sum (λ i, b) = a * b :=
by rw [finset.sum_const, finset.card_univ, fintype.card_fin, add_monoid.smul_eq_mul, nat.cast_id]

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 18:10):

That's the way (or you can use simp instead of the last couple of things, I should think)

view this post on Zulip Kevin Buzzard (Jun 21 2019 at 18:11):

example (a b : ):  finset.univ.sum (λ i : fin a, b)=a*b :=
by simp [finset.sum_const, finset.card_univ, fintype.card_fin]

view this post on Zulip Adrian Chu (Jun 22 2019 at 04:49):

Thanks guys!

view this post on Zulip Adrian Chu (Jun 22 2019 at 08:01):

What command should I use to define a function f(x) from N to N with two cases, namely x >= some fixed n and x < n?

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 08:02):

Lean has if ... then ... else

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 08:03):

The tactic you need to know to introduce it is split_ifs.

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 08:04):

if...then...else is harder to use than you might think, because Lean will by default refuse to do a case split on a condition unless it knows an algorithm for deciding whether the condition is true or not. In your case this should be no trouble.

view this post on Zulip Adrian Chu (Jun 22 2019 at 08:15):

given a function f : fin n -> N, how can I extend it to N -> N by defining it to be zero when the input is >= n ?

view this post on Zulip Mario Carneiro (Jun 22 2019 at 08:16):

if h : x < n then f <x, h> else 0

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 10:01):

You shouldn't think of fin n as some sort of subset of nat. There's a map from fin n to nat which forgets part of the structure. From your recent questions you seen to think that a term of type fin n is a nat. It's not -- it's a pair.

view this post on Zulip Adrian Chu (Jun 22 2019 at 10:09):

You shouldn't think of fin n as some sort of subset of nat. There's a map from fin n to nat which forgets part of the structure. From your recent questions you seen to think that a term of type fin n is a nat. It's not -- it's a pair.

ya, i know, i just didn't know that we can directly write if h : x < n instead of if x<n

view this post on Zulip Adrian Chu (Jun 22 2019 at 10:14):

What is the correct syntax to define such a function def f (x : ℕ) : ℕ := if x < 10 then x else f (x-3) recursively? (since I don't want to use mod for some other reason)

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 11:11):

You will have to prove, somehow, that your function is well-defined. One thing you could do is just use the equation compiler, but that would stink a bit in this situation. You could define f zero = 0, f 1 = 1, ..., and then f (n+10) to be f(n+7). That might work.

view this post on Zulip Mario Carneiro (Jun 22 2019 at 11:13):

you only have to go up to n+3

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 11:13):

I'm not so sure it's as easy as that, because f(7) is not f(4)

view this post on Zulip Mario Carneiro (Jun 22 2019 at 11:14):

def f :   
| x@(y+3) := if x < 10 then x else f y
| x := x

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 11:15):

Nice!

view this post on Zulip Mario Carneiro (Jun 22 2019 at 11:15):

it still has 4 cases though

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 11:15):

I have never had to push the equation compiler to its limits, so I don't really know these tricks.

view this post on Zulip Mario Carneiro (Jun 22 2019 at 11:16):

try replacing 3 with 100

view this post on Zulip Adrian Chu (Jun 22 2019 at 11:48):

I see... Thanks.

view this post on Zulip Adrian Chu (Jun 22 2019 at 11:59):

def f :   
| x@(y+3) := if x < 10 then x else f y
| x := x

But can someone please explain a bit what does this means?

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 12:00):

Have you read the section about the equation compiler in TPIL?

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 12:00):

It says "if x = y + 3 for some other nat y then do the first thing, else do the second thing"

view this post on Zulip Adrian Chu (Jun 22 2019 at 12:03):

well not yet. you are right, i should read it first :)

view this post on Zulip Adrian Chu (Jun 22 2019 at 14:58):

Now i have read the relevant sections in TPIL. But I still got a problem: How can I check the well foundedness of

def f :  ×    × 
| (y+3, z+3) := if ((y+3) < 10)  ((z+3) < 10) then (y+3, z+3) else f (y, z)
| (y, z) := (y, z)

?

view this post on Zulip Kevin Buzzard (Jun 22 2019 at 16:22):

Some hints are here: https://github.com/leanprover-community/mathlib/blob/master/docs/extras/well_founded_recursion.md

view this post on Zulip Bryan Gin-ge Chen (Jun 23 2019 at 02:19):

I had a go at this here (web editor link):

import data.prod
/-
set_option pp.all true
-/

def f :  ×    × 
| (y+3, z+3) := have h : (y, z).lex (<) (<) (y+3, z+3) := begin
  simp [prod.lex_def],
  have hy : y < y + 3 := nat.lt_add_of_pos_right (dec_trivial),
  exact or.inl hy,
end,
  if ((y+3) < 10)  ((z+3) < 10) then
    (y+3, z+3) else f (y, z) -- error here, see below
| (y, z) := (y, z)

However, I'm not able to satisfy the equation compiler either:

failed to prove recursive application is decreasing, well founded relation
  @has_well_founded.r (ℕ × ℕ)
    (@prod.has_well_founded ℕ ℕ (@has_well_founded_of_has_sizeof ℕ nat.has_sizeof)
       (@has_well_founded_of_has_sizeof ℕ nat.has_sizeof))
Possible solutions:
  - Use 'using_well_founded' keyword in the end of your definition to specify tactics for synthesizing well founded relations and decreasing proofs.
  - The default decreasing tactic uses the 'assumption' tactic, thus hints (aka local proofs) can be provided using 'have'-expressions.
The nested exception contains the failure state for the decreasing tactic.
nested exception message:
match failed
state:
f : ℕ × ℕ → ℕ × ℕ,
y z : ℕ,
h : prod.lex has_lt.lt has_lt.lt (y, z) (y + 3, z + 3)
⊢ prod.lex has_lt.lt has_lt.lt (y, z) (y + 3, z + 3)

(Isn't h the same thing as the goal? Using pp.all true doesn't reveal any differences either)

I think it's easier to define f by working with the curried version, like this:

def f_curry :      × 
| (y+3) (z+3) := if ((y+3) < 10)  ((z+3) < 10) then
    (y+3, z+3) else f_curry y z
| y z := (y, z)

def f' (p :  × ) :  ×  := f_curry p.1 p.2

view this post on Zulip Mario Carneiro (Jun 23 2019 at 02:26):

I think, from the trajectory of the questions, that @Adrian Chu wants to know how to do general recursions, rather than breaking them down into structural recursions. It looks like this:

def f :  ×    × 
| (x, y) :=
  if h : x < 10  y < 10 then (x, y) else
  have has_well_founded.r (x - 3, y - 3) (x, y), from sorry,
  f (x - 3, y - 3)
using_well_founded { dec_tac := `[assumption] }

You have to give a proof that (x - 3, y - 3) < (x, y) according to some well founded relation. The default one here is lexicographic order on the natural numbers, which works in this case but may need to be replaced with something else in other examples

view this post on Zulip Adrian Chu (Jun 23 2019 at 03:57):

I see.. I didn't know we have `[assumption]

view this post on Zulip Adrian Chu (Jun 23 2019 at 03:59):

I am trying to prove the following variant of Bazout lemma:

lemma baz (a : ) (b : ) (h: nat.coprime a b):  x : ,  y : , a*x + 1 = b*y :=
sorry

As pointed before, we can use gcd_a and gcd_b

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:04):

but the trouble is gcd_a, gcd_b can be negative

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:05):

so my plan is to keep adding multiples of a*b to -gcd_a a b and gcd_b a b repsectively until they are both >= 0

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:07):

But I run into 2 problems. First, (as an example,) given a recursive function like

def f :    
| (y+3) := if h:(y+3<10) then (y+3) else f y
| y := y

how can we show that f x < 10 for all x ?

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:09):

second, given a function f from Z to Z and a proof that f x >=0 for all x, how can we define a new function F from Z to N using f?

view this post on Zulip Mario Carneiro (Jun 23 2019 at 04:35):

Rather than "repeatedly adding multiples of a*b", just add k*a*b for some k. This avoids all the mess of determining any well founded recursion, but it leaves the question - what is k?

view this post on Zulip Mario Carneiro (Jun 23 2019 at 04:36):

Also baz is really obviously false when a = b = 0

view this post on Zulip Mario Carneiro (Jun 23 2019 at 04:36):

or more generally when they aren't coprime

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:44):

Also baz is really obviously false when a = b = 0

oops, I carelessly left out the coprime condition. now fixed

view this post on Zulip Mario Carneiro (Jun 23 2019 at 04:46):

If a and b are both nonzero, then a*b is also nonzero, so it is at least 1 and hence k*a*b is at least k. So you can pick k to be gcd_a a b and then k*a*b - gcd_a a b will be nonnegative

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:49):

Rather than "repeatedly adding multiples of a*b", just add k*a*b for some k. This avoids all the mess of determining any well founded recursion, but it leaves the question - what is k?

Yes, I have thought of that, we can choose k=max (nat_abs (nat.gcd_a x y)) (nat_abs (nat.gcd_b x y))

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:49):

yes yours is simpler!

view this post on Zulip Mario Carneiro (Jun 23 2019 at 04:50):

You can use either to_nat or nat_abs to turn a nonnegative int into a nat

view this post on Zulip Adrian Chu (Jun 23 2019 at 04:52):

ok, let me try now

view this post on Zulip Adrian Chu (Jun 23 2019 at 05:02):

If a and b are both nonzero, then a*b is also nonzero, so it is at least 1 and hence k*a*b is at least k. So you can pick k to be gcd_a a b and then k*a*b - gcd_a a b will be nonnegative

i was mistaken. we should add k*b to -gcd_a a b and add k*a to gcd_b a b

view this post on Zulip Adrian Chu (Jun 23 2019 at 05:04):

and take k = max (nat_abs (nat.gcd_a a b)) (nat_abs (nat.gcd_b a b))

view this post on Zulip Adrian Chu (Jun 23 2019 at 11:26):

May I ask how to prove
theorem test (a : ℤ) (ha : a >= 0) : a = nat_abs a ?

view this post on Zulip Kevin Buzzard (Jun 23 2019 at 11:26):

Does cases on a work?

view this post on Zulip Kevin Buzzard (Jun 23 2019 at 11:26):

Alternatively just use library_search.

view this post on Zulip Kevin Buzzard (Jun 23 2019 at 11:27):

You might want to import data.int.basic before you search

view this post on Zulip Kevin Buzzard (Jun 23 2019 at 11:28):

Here's where I'm up to: https://github.com/kbuzzard/xena/blob/cd8e0de23adf8c0e7c56d39f1b6f5a55d93bf6ef/Examples/mario_glueing.lean#L144

view this post on Zulip Kenny Lau (Jun 23 2019 at 12:17):

open int
theorem test : Π a : , 0  a  a = nat_abs a
| (of_nat n) h := rfl

view this post on Zulip Kenny Lau (Jun 23 2019 at 12:18):

import data.int.basic
open int
theorem test (a : ) (ha : 0  a) : a = nat_abs a :=
(nat_abs_of_nonneg ha).symm

view this post on Zulip Adrian Chu (Jun 23 2019 at 14:22):

Ah, so we already have this theorem. Thanks

view this post on Zulip Adrian Chu (Jun 23 2019 at 14:50):

I am proving using calc, the first and last expression has type nat but some of the intermediate steps have type int

view this post on Zulip Mario Carneiro (Jun 23 2019 at 14:51):

apply int.coe_nat_inj

view this post on Zulip Adrian Chu (Jun 23 2019 at 14:51):

which hence give type mismatch error

view this post on Zulip Mario Carneiro (Jun 23 2019 at 14:51):

before starting the calc block

view this post on Zulip Adrian Chu (Jun 23 2019 at 15:27):

can someone kindly write a simple example to illustrate how a proof involving int.coe_nat_inj and calc should look like? since I can't find this in mathlib

view this post on Zulip Mario Carneiro (Jun 23 2019 at 15:40):

you can't find the theorem?

view this post on Zulip Mario Carneiro (Jun 23 2019 at 15:41):

show me your proof and I'll fix it

view this post on Zulip Mario Carneiro (Jun 23 2019 at 15:44):

example (x y : ) (a : ) (h1 : a = x) (h2 : a = y) : x = y :=
int.coe_nat_inj $ calc
   x = a : h1.symm
  ... = y : h2

view this post on Zulip Adrian Chu (Jun 23 2019 at 15:47):

wow thanks.

view this post on Zulip Adrian Chu (Jun 23 2019 at 15:48):

lemma baz (a : ) (b : ) (h : nat.coprime a b) :  x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -nat.gcd_a a b + (gcd_b a b)*k,
  let y := nat.gcd_b a b + (gcd_a a b)*k,
  have hx : x = nat_abs x := sorry,
  have hy : y = nat_abs y := sorry,
  fapply exists.intro,
  exact nat_abs x,
  fapply exists.intro,
  exact nat_abs y,
  calc
    a*(nat_abs x) + 1 = b*(nat_abs y) : by sorry
end

view this post on Zulip Adrian Chu (Jun 23 2019 at 15:48):

bit by bit, I'm first dealing with the last sorry. do you think i should use int.coe_nat_inj here?

view this post on Zulip Mario Carneiro (Jun 23 2019 at 15:52):

lemma baz (a : ) (b : ) (h : nat.coprime a b) :  x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -nat.gcd_a a b + (gcd_b a b)*k,
  let y := nat.gcd_b a b + (gcd_a a b)*k,
  have hx : x = nat_abs x := sorry,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a*(nat_abs x) + 1 : by simp
      ... = a * x + 1 : by rw  hx
      ... = b * y : by sorry
      ... = b * (nat_abs y) : by rw  hy
      ... = (b * (nat_abs y) : ) : by simp
end

view this post on Zulip Adrian Chu (Jun 23 2019 at 15:59):

thx, i'll keep working on it

view this post on Zulip Adrian Chu (Jun 23 2019 at 16:20):

what should replace sorry in this step? +_+ why doesn't left_distrib works?

a*(-nat.gcd_a a b + b*k) + 1
... = - a*nat.gcd_a a b + a*b*k + 1 : by sorry

view this post on Zulip Mario Carneiro (Jun 23 2019 at 16:21):

it's not just left_distrib, you also associated + and distributed - over *

view this post on Zulip Mario Carneiro (Jun 23 2019 at 16:22):

simp [mul_add] should do it

view this post on Zulip Adrian Chu (Jun 23 2019 at 16:23):

by simp [mul_add] doesnt work...

view this post on Zulip Mario Carneiro (Jun 23 2019 at 16:24):

look at what you get, and add theorems that make them look more alike

view this post on Zulip Adrian Chu (Jun 23 2019 at 16:28):

i need mul_assoc !!

view this post on Zulip Adrian Chu (Jun 24 2019 at 05:05):

lemma baz (a : ) (b : ) (h : nat.gcd a b = 1) :  x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -nat.gcd_a a b + b*k,
  let y := nat.gcd_b a b + a*k,
  have hx : x = nat_abs x := sorry,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a * x + 1 : by simp [hx.symm]
      ... = - a*nat.gcd_a a b + nat.gcd a b + a*b*k : by simp [mul_add, mul_assoc, add_assoc, h]
      ... = - a*nat.gcd_a a b + a*nat.gcd_a a b + b*nat.gcd_b a b + a*b*k : by sorry
      ... = b*nat.gcd_b a b + b*a*k : by simp [add_neg_self, mul_comm]
      ... = b * y : by simp [mul_add, mul_assoc]
      ... = (b * (nat_abs y) : ) : by simp [hy.symm]
end

view this post on Zulip Adrian Chu (Jun 24 2019 at 05:06):

I have trouble to finish the last sorry (on the 5th last line)

view this post on Zulip Adrian Chu (Jun 24 2019 at 05:07):

I know that i should use gcd_eq_gcd_ab, but type problems of Z and N keep coming up, and I don't know how to use ↑ correctly

view this post on Zulip Mario Carneiro (Jun 24 2019 at 06:34):

make sure to bracket things correctly so that the work is isolated

view this post on Zulip Mario Carneiro (Jun 24 2019 at 06:34):

when you write a+b+c+d that gets associated as ((a+b)+c)+d, so you are mixing different concerns

view this post on Zulip Mario Carneiro (Jun 24 2019 at 06:36):

lemma baz (a : ) (b : ) (h : nat.gcd a b = 1) :  x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -nat.gcd_a a b + b*k,
  let y := nat.gcd_b a b + a*k,
  have hx : x = nat_abs x := sorry,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a * x + 1 : by simp [hx.symm]
      ... = - a*nat.gcd_a a b + nat.gcd a b + a*b*k : by simp [mul_add, mul_assoc, add_assoc, h]
      ... = - a*nat.gcd_a a b + (a*nat.gcd_a a b + b*nat.gcd_b a b) + a*b*k : by rw gcd_eq_gcd_ab
      ... = b*nat.gcd_b a b + b*a*k : by simp [add_neg_self, mul_comm]
      ... = b * y : by simp [mul_add, mul_assoc]
      ... = (b * (nat_abs y) : ) : by simp [hy.symm]
end

view this post on Zulip Adrian Chu (Jun 24 2019 at 06:38):

nope, this doesnt work, it has error message :

rewrite tactic failed, did not find instance of the pattern in the target expression
gcd ?m_4 ?m_5
state:
a b : ℕ,
h : nat.gcd a b = 1,
k : ℕ := max (nat_abs (gcd_a ↑a ↑b)) (nat_abs (gcd_b ↑a ↑b)),
x : ℤ := -nat.gcd_a a b + ↑b * ↑k,
y : ℤ := nat.gcd_b a b + ↑a * ↑k,
hx : x = ↑(nat_abs x),
hy : y = ↑(nat_abs y)
⊢ -↑a * nat.gcd_a a b + ↑(nat.gcd a b) + ↑a * ↑b * ↑k =
-↑a * nat.gcd_a a b + (↑a * nat.gcd_a a b + ↑b * nat.gcd_b a b) + ↑a * ↑b * ↑k
state:
a b : ℕ,
h : nat.gcd a b = 1,
k : ℕ := max (nat_abs (gcd_a ↑a ↑b)) (nat_abs (gcd_b ↑a ↑b)),
x : ℤ := -nat.gcd_a a b + ↑b * ↑k,
y : ℤ := nat.gcd_b a b + ↑a * ↑k,
hx : x = ↑(nat_abs x),
hy : y = ↑(nat_abs y)
⊢ ↑(a * nat_abs x + 1) = ↑(b * nat_abs y)

view this post on Zulip Mario Carneiro (Jun 24 2019 at 06:52):

this works for me:

import data.int.gcd
open nat int
lemma baz (a : ) (b : ) (h : nat.gcd a b = 1) :  x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -nat.gcd_a a b + b*k,
  let y := nat.gcd_b a b + a*k,
  have hx : x = nat_abs x := sorry,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a * x + 1 : by simp [hx.symm]
      ... = - a*nat.gcd_a a b + nat.gcd a b + a*b*k : by simp [mul_add, mul_assoc, add_assoc, h]
      ... = - a*nat.gcd_a a b + (a*nat.gcd_a a b + b*nat.gcd_b a b) + a*b*k : by rw gcd_eq_gcd_ab
      ... = b*nat.gcd_b a b + b*a*k : by simp [add_neg_self, mul_comm]
      ... = b * y : by simp [mul_add, mul_assoc]
      ... = (b * (nat_abs y) : ) : by simp [hy.symm]
end

view this post on Zulip Mario Carneiro (Jun 24 2019 at 06:54):

it's not clear to me what you have open, but it seems to work with nat and int open

view this post on Zulip Mario Carneiro (Jun 24 2019 at 06:55):

maybe you have something else imported so that gcd means something else?

view this post on Zulip Adrian Chu (Jun 24 2019 at 07:14):

I opened euclidean domain, thats why. but actually i don't need it. Thanks!

view this post on Zulip Adrian Chu (Jun 24 2019 at 09:45):

lemma baz (a : ) (b : ) (h : nat.gcd a b = 1) :  x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -nat.gcd_a a b + b*k,
  let y := nat.gcd_b a b + a*k,
  have hxx : 0  x :=
    calc 0  -nat.gcd_a a b + b*nat_abs (gcd_a a b) : by sorry
    ...  -nat.gcd_a a b + b*(max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)))
           : by sorry --simp [le_max_left]
    ... = -nat.gcd_a a b + b*k : by sorry--simp
    ... = x : by simp,

this time is about the 2nd and 3rd sorry. why dont those corresponding commands (which I commented above) work?

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:32):

I insert my canonical remark. [It would be easier for people like me if you could just post fully working code. I need to open things, maybe import things, etc; can you do this part of the job for me please?].

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:34):

But the answer to your question might be that the first sorry won't work because simp is designed to prove equalities, not inequalities, and the second proof should probably be rfl because it looks to me like it's true by definition.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:36):

All the simplifier does is that it proves things of the form X = Y by attempting to simplify both sides into a canonical form and then checking that they're true by definition. A simp lemma is of the form A = B, and if A is a sub-term in X then the simplifier will replace A by B; that's why simp lemmas should have (complicated) = (simpler) in that order.

view this post on Zulip Adrian Chu (Jun 24 2019 at 11:42):

I insert my canonical remark. [It would be easier for people like me if you could just post fully working code. I need to open things, maybe import things, etc; can you do this part of the job for me please?].

ok sure!

import data.int.basic data.int.gcd
open nat int

lemma baz (a : ) (b : ) (h : nat.gcd a b = 1) :  x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -gcd_a a b + b*k,
  let y := gcd_b a b + a*k,
  have hxx : x  0 :=
    calc 0  -gcd_a a b + b*nat_abs (gcd_a a b) : by sorry
    ...  -gcd_a a b + b*(max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b))) : by sorry --simp [le_max_left]
    ... = -gcd_a a b + b*k : sorry
    ... = x : by simp,
  have hx : x = nat_abs x := (nat_abs_of_nonneg hxx).symm,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a * x + 1 : by simp [hx.symm]
      ... = - a*gcd_a a b + nat.gcd a b + a*b*k : by simp [mul_add, mul_assoc, add_assoc, h]
      ... = - a*gcd_a a b + (a*gcd_a a b + b*gcd_b a b) + a*b*k : by rw gcd_eq_gcd_ab
      ... = b*gcd_b a b + b*a*k : by simp [add_neg_self, mul_comm]
      ... = b * y : by simp [mul_add, mul_assoc]
      ... = (b * (nat_abs y) : ) : by simp [hy.symm]
end

view this post on Zulip Adrian Chu (Jun 24 2019 at 11:44):

for the 3rd sorry, rfl doesnt work...

view this post on Zulip Adrian Chu (Jun 24 2019 at 11:44):

All the simplifier does is that it proves things of the form X = Y by attempting to simplify both sides into a canonical form and then checking that they're true by definition. A simp lemma is of the form A = B, and if A is a sub-term in X then the simplifier will replace A by B; that's why simp lemmas should have (complicated) = (simpler) in that order.

ah, i see

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:47):

    calc 0  -gcd_a a b + b*nat_abs (gcd_a a b) : by sorry

a=1 and b=0 is a counterexample to this. This is the problem with skipping stuff -- even if your later two sorries are fixed the code might be unusable anyway.

view this post on Zulip Adrian Chu (Jun 24 2019 at 11:49):

no, we cant have a=1, b=0 because of the hypothesis h

view this post on Zulip Mario Carneiro (Jun 24 2019 at 11:49):

1 and 0 are coprime

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:49):

The problem with the final sorry is that k is defined using the max on nat, and the other max is on int.

view this post on Zulip Adrian Chu (Jun 24 2019 at 11:50):

oh no! :(

view this post on Zulip Adrian Chu (Jun 24 2019 at 11:50):

i need to add more hypothesis then

view this post on Zulip Adrian Chu (Jun 24 2019 at 11:51):

The problem with the final sorry is that k is defined using the max on nat, and the other max is on int.

how should I get around?

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:54):

There might be some magic tactic which does it, I've not tried those new cast tactics. If not, then you have to fix things up yourself.

My recommendation would be to change every single variable into an int as soon as possible, make all the problems go away, and then just prove that various things are >= 0 at the end and then cast them back to nats.

view this post on Zulip Mario Carneiro (Jun 24 2019 at 11:54):

I would keep the max on nat, because that's the definition of k

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:54):

You're just in the typical nat/int hell which several of my students found themselves in over the summer. In my mind, if your proof uses ints, then why even use nats at all? Just use ints with a proof that they're >= 0.

view this post on Zulip Mario Carneiro (Jun 24 2019 at 11:55):

it might help to write some up arrows because it's important to know where they are

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:55):

Maybe this would be a great place to test out the cast tactics. Did they get written up in the tactics docs?

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 11:56):

https://github.com/leanprover-community/mathlib/blob/master/docs/tactics.md

They're right at the bottom. Maybe these can help. I've never used them though.

view this post on Zulip Mario Carneiro (Jun 24 2019 at 11:56):

to use the cast tactics, you have to actually have a specific goal that you can use them with

view this post on Zulip Mario Carneiro (Jun 24 2019 at 11:57):

distributing the arrows in this case is easily enough done by simp, that's already working in the example

view this post on Zulip Adrian Chu (Jun 24 2019 at 13:27):

yes, i should definitely use int instead of nat. because I have to add the condition that a, b >0 anyway, as you pointed out

view this post on Zulip Adrian Chu (Jun 24 2019 at 13:36):

but since gcd_a and gcd_b are for nat instead of int, other troubles will arise...

view this post on Zulip Adrian Chu (Jun 24 2019 at 14:24):

import data.int.basic data.int.gcd
open nat int

lemma baz (a : ) (b : ) (ha : a > 0) (hb : b > 0) (h : nat.gcd a b = 1) :
     x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -gcd_a a b + b*k,
  let y := gcd_b a b + a*k,
  have hxx : x  0 :=
    calc 0  -gcd_a a b + b*(nat_abs (gcd_a a b)) : by sorry
    ... = -gcd_a a b + b*(nat_abs (gcd_a a b)) : by simp
    ...  -gcd_a a b + b*(max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b))) :
        by sorry -- rw le_max_left
    ... = -gcd_a a b + b*k : by simp
    ... = x : by simp,
  have hx : x = nat_abs x := (nat_abs_of_nonneg hxx).symm,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a * x + 1 : by simp [hx.symm]
      ... = - a*gcd_a a b + nat.gcd a b + a*b*k : by simp [mul_add, mul_assoc, add_assoc, h]
      ... = - a*gcd_a a b + (a*gcd_a a b + b*gcd_b a b) + a*b*k : by rw gcd_eq_gcd_ab
      ... = b*gcd_b a b + b*a*k : by simp [add_neg_self, mul_comm]
      ... = b * y : by simp [mul_add, mul_assoc]
      ... = (b * (nat_abs y) : ) : by simp [hy.symm]
end

view this post on Zulip Adrian Chu (Jun 24 2019 at 14:25):

now i have changed the definition of k so that everything should be in int. why rw le_max_left still doesnt work?

view this post on Zulip Adrian Chu (Jun 24 2019 at 15:05):

oh, i know why, its because i need a proof for (b:nat)(a:int)(c:int)(a<=c) : b*a <= b*c. i guess this is proven somewhere already?

view this post on Zulip Adrian Chu (Jun 24 2019 at 15:25):

import data.int.basic data.int.gcd
open nat int

lemma baz (a : ) (b : ) (ha : a  1) (hb : b  1) (h : nat.gcd a b = 1) :
     x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -gcd_a a b + b*k,
  let y := gcd_b a b + a*k,
  have hxx : x  0 :=
    calc (0 : ) = 0 * nat_abs (gcd_a a b) : by simp
    ...  (b - 1) * (nat_abs (gcd_a a b)) : by sorry -- rw hb ...?
    ...  (b - 1) * (nat_abs (gcd_a a b)) : by simp
    ... = b*(nat_abs (gcd_a a b)) - 1*(nat_abs (gcd_a a b))
        : sub_mul (b) (1) (nat_abs (gcd_a a b))
    ...  b*(nat_abs (gcd_a a b)) - gcd_a a b : by sorry -- ...?
    ... = -gcd_a a b + b*(nat_abs (gcd_a a b)) : by simp
    ...  -gcd_a a b + b*(max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b))) :
        by sorry -- rw le_max_left ...?
    ... = -gcd_a a b + b*k : by simp
    ... = x : by simp,
  have hx : x = nat_abs x := (nat_abs_of_nonneg hxx).symm,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a * x + 1 : by simp [hx.symm]
      ... = - a*gcd_a a b + nat.gcd a b + a*b*k : by simp [mul_add, mul_assoc, add_assoc, h]
      ... = - a*gcd_a a b + (a*gcd_a a b + b*gcd_b a b) + a*b*k : by rw gcd_eq_gcd_ab
      ... = b*gcd_b a b + b*a*k : by simp [add_neg_self, mul_comm]
      ... = b * y : by simp [mul_add, mul_assoc]
      ... = (b * (nat_abs y) : ) : by simp [hy.symm]
end

view this post on Zulip Adrian Chu (Jun 24 2019 at 15:29):

OK, I can finally see the end. Only 3 sorry's (the first 3) are left to be filled, which I believe can be done using existing theorems. Can someone please tell me what the right commands are? Thanks!

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 15:53):

Did you try library search?

view this post on Zulip Adrian Chu (Jun 24 2019 at 15:58):

How to do library_search? :exhausted:

view this post on Zulip Reid Barton (Jun 24 2019 at 15:58):

Read the documentation for library_search?

view this post on Zulip Reid Barton (Jun 24 2019 at 16:00):

in https://github.com/leanprover-community/mathlib/blob/master/docs/tactics.md

view this post on Zulip Adrian Chu (Jun 24 2019 at 16:08):

Read the documentation for library_search?

Ya, I just noticed this, embarrassing lol

view this post on Zulip Adrian Chu (Jun 24 2019 at 16:16):

library_search times out :(

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 16:24):

So your first sorry is a proof of

 0 * nat_abs (gcd_a a b) ≤ (b - 1) * (nat_abs (gcd_a a b))

You wrote rw hb, and here hb : b >= 1. NB that's not the canonical way to write that inequality, the canonical way is 1 <= b. Yes, it does make a difference :-/

But you probably know what rw really does. For rw h to work, h must really be of the form A = B, and then rw takes the A's and replaces them with B's. So this is not a rewrite at all. What it is is a theorem. It's the theorem that x <= y and c >= 0 then x * c <= y * c. And that theorem will have a name, which you can either guess (once you understand the naming conventions), remember (once you've used Lean for a while) or look up using library-search (if it works).

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 16:25):

example (a b c : ) (h : 0  c) (h2 : a  b) : a * c  b * c := by library_search -- works!

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 16:30):

Your second sorry seems to be of the form

↑b*↑(nat_abs (gcd_a a b)) - ↑1*↑(nat_abs (gcd_a a b)) ≤ b*(nat_abs (gcd_a a b)) - gcd_a a b

Why are you proving an inequality? It looks to me like this should be an equality. It seems to me that there are three issues here. The first is the inequality. The second is that a bunch of arrows disappeared (either because you didn't write them and they're still there really, or because you really are switching from integers to naturals). To sort that out you'll either need some cast tactic, or you should just work with integers all the way through. The final thing is the issue that you are implicitly assuming 1 * x = x. That's a theorem, it's not true by definition, so it will have a name (I guess the name is one_mul), and that theorem needs to be applied somehow (by rewriting I guess) to get rid of that 1.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 16:39):

The third sorry is

-gcd_a a b + b*↑(nat_abs (gcd_a a b))
 ≤ -gcd_a a b + b*(max ↑(nat_abs (gcd_a a b)) ↑(nat_abs (gcd_b a b)))

You want to use le_max_left but again there are several steps which you're leaving out. As well as le_max_left there's the analogous theorem for the first sorry, but this time with conclusion c * a <= c * b (different conclusion = different theorem name), and you're also using the fact that a <= b implies c + a <= c + b. I think the simplifier is not well suited for these questions -- but I might be wrong. In some sense this is the problem with calc mode. You could just enter tactic mode again with a begin end, and then do the rewriting yourself.

    calc (0 : ) = 0 * nat_abs (gcd_a a b) : by simp
    ...  (b - 1) * (nat_abs (gcd_a a b)) : by sorry -- rw hb ...?
    ...  (b - 1) * (nat_abs (gcd_a a b)) : by simp
    ... = b*(nat_abs (gcd_a a b)) - 1*(nat_abs (gcd_a a b))
        : sub_mul (b) (1) (nat_abs (gcd_a a b))
    ...  b*(nat_abs (gcd_a a b)) - gcd_a a b : by sorry -- ...?
    ... = -gcd_a a b + b*(nat_abs (gcd_a a b)) : by simp
    ...  -gcd_a a b + b*(max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b))) :
        begin
          apply add_le_add_left,
          apply mul_le_mul_of_nonneg_left,
            exact le_max_left _ _,
          -- etc
          sorry
        end
    ... = -gcd_a a b + b*k : by simp

Tactic mode is the best mode really. You wrote rw le_max_left but that doesn't even make sense; you can only rewrite equalities. You are not thinking about what is really happening. What is really happening is that you are constantly applying little lemmas. The proof of c + d * a <= c + d * (max a b) is really not a rewrite. It is an application of several unrelated facts about inequalities, each of which has been painstakingly proved by the library creators. One of them is le_max_left but there are others.

view this post on Zulip Adrian Chu (Jun 24 2019 at 16:43):

import data.int.basic data.int.gcd tactic.library_search algebra.ordered_ring
open nat int

lemma baz (a : ) (b : ) (ha : a  1) (hb : b  1) (h : nat.gcd a b = 1) :
     x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b)),
  let x := -gcd_a a b + b*k,
  let y := gcd_b a b + a*k,
  have hg : 0  nat_abs (gcd_a a b) := by simp,
  have hb : 0  b - 1 := by simp,
  have hxx : x  0 :=
    calc (0 : ) = 0 * nat_abs (gcd_a a b) : by simp
    ...  (b - 1) * (nat_abs (gcd_a a b)) :
        by exact mul_le_mul_of_nonneg_right hb hg
    ...  (b - 1) * (nat_abs (gcd_a a b)) : by simp
    ... = b*(nat_abs (gcd_a a b)) - 1*(nat_abs (gcd_a a b)) :
        sub_mul (b) (1) (nat_abs (gcd_a a b))
    ... = b*(nat_abs (gcd_a a b)) - nat_abs (gcd_a a b) : by simp
    ...  b*(nat_abs (gcd_a a b)) - gcd_a a b : by sorry
    ... = -gcd_a a b + b*(nat_abs (gcd_a a b)) : by simp
    ...  -gcd_a a b + b*(max (nat_abs (gcd_a a b)) (nat_abs (gcd_b a b))) :
        by sorry -- rw le_max_left ...?
    ... = -gcd_a a b + b*k : by simp
    ... = x : by simp,
  have hx : x = nat_abs x := (nat_abs_of_nonneg hxx).symm,
  have hy : y = nat_abs y := sorry,
  existsi nat_abs x,
  existsi nat_abs y,
  apply int.coe_nat_inj,
  calc
    (a*(nat_abs x) + 1 : ) = a * x + 1 : by simp [hx.symm]
      ... = - a*gcd_a a b + nat.gcd a b + a*b*k : by simp [mul_add, mul_assoc, add_assoc, h]
      ... = - a*gcd_a a b + (a*gcd_a a b + b*gcd_b a b) + a*b*k : by rw gcd_eq_gcd_ab
      ... = b*gcd_b a b + b*a*k : by simp [add_neg_self, mul_comm]
      ... = b * y : by simp [mul_add, mul_assoc]
      ... = (b * (nat_abs y) : ) : by simp [hy.symm]
end

view this post on Zulip Adrian Chu (Jun 24 2019 at 16:44):

This is my attempt to resolve the first sorry, but I got an enormous error message. As for the second sorry, it should be an inequality since gcd_a can be negative. I will come back to this tomorrow, its so late at night. Anyway, thanks~

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 16:48):

As for the second sorry, it should be an inequality since gcd_a can be negative.

Oh, apologies! I thought these were the nat ones. In which case my comments apply about how things like a <= b implies c - a >= c - b are not immediate or automatic, they are theorems which need applying. You'll also need one_mul, and the fact that z <= abs z.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 16:52):

The enormous error message is only enormous because Lean has expanded everything out for you to explain what the problem is. If it just said "I was expecting a proof that something was <= something, and you gave me a proof that something was <= something" then it would be confusing. But

type mismatch at application
  mul_le_mul_of_nonneg_right hb
term
  hb
has type
  @has_le.le nat nat.has_le 0
    (@has_sub.sub nat nat.has_sub
       (@coe nat nat (@coe_to_lift nat nat (@coe_base nat nat (@nat.cast_coe nat nat.has_zero nat.has_one nat.has_add)))
          b)
       1)
but is expected to have type
  @has_le.le int
    (@preorder.to_has_le int
       ...

says that hb has type @has_le.le nat ... (i.e. it's a proof that one nat is <= another nat) and you attempted to insert it into a function which was expecting something of type @has_le.le int ... i.e. expecting a proof that one int is <= another int.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 16:55):

replacing by exact mul_le_mul_of_nonneg_right with the more refined "attempt to solve the goal with this function but give me the inputs as new goals" refine tactic

begin refine mul_le_mul_of_nonneg_right _ _, sorry, sorry end

shows you what the problem is. You now need to fill in those two holes, and the results you have are not good enough because they have the wrong type. Did I mention the idea of just using integers everywhere by the way?

view this post on Zulip Adrian Chu (Jun 24 2019 at 17:00):

Did I mention the idea of just using integers everywhere by the way?

but gcd_a, gcd_b are defined for nat instead of int

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 17:00):

But this issue is just a general pain in type theory. Do you understand how to use these new cast tactics? The first hole needs a resolution of this issue

hb : 0 ≤ ↑b - 1
⊢ 0 ≤ ↑b - 1

Here your hypothesis hb has an arrow in, which turns out to be a cast from nat to nat. You can see all the gory details of everything by set_option pp.all true. Setting this option will give you some real insight into how the computer is thinking about what you are doing. In particular you cannot cast from a nat to an int by just putting an up-arrow -- Lean doesn't know where you're casting to.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 17:01):

Did I mention the idea of just using integers everywhere by the way?

but gcd_a, gcd_b are defined for nat instead of int

Feed them absolute values of ints? I don't know if this is a feasible solution.

view this post on Zulip Adrian Chu (Jun 24 2019 at 17:04):

Did I mention the idea of just using integers everywhere by the way?

but gcd_a, gcd_b are defined for nat instead of int

Feed them absolute values of ints? I don't know if this is a feasible solution.

i will try tomorrow

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 17:11):

I don't know if this is feasible. All I see when I look at your code though is a bunch of stuff about ints, with subtractions etc. You might well find the int analogue of the gcd_a functions in data.int.basic somewhere or maybe even in core.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 17:27):

Maybe now we have norm_cast you don't need to make everything an integer. This little lemma might be a nice test case. I just tried it on the first sorry and had positive results:

    calc (0 : ℤ) = 0 * nat_abs (gcd_a a b) : by simp
    ... ≤ (↑b - 1) * (nat_abs (gcd_a a b)) :
        begin apply mul_le_mul_of_nonneg_right,
          {norm_cast at hb ⊢, exact hb},
          {norm_cast, simp}
        end

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 17:32):

For the next one you need the theorem that a <= b implies c - b <= c - a (note how I always stick with <=, otherwise there would be lots of ways of saying inequalities; there is a "canonical form" for many expressions in Lean and it is only slowly dawning on me how important this is in practice). To find that theorem you see that the conclusion is of the form "a subtraction is less than or equal to a subtraction" so I type "apply sub_le_sub" and then I press ctrl-space in VS Code and see a list of all Lean's theorems that start sub_le_sub and all their types too, so it's easy to find the one I want. That's another way of finding out the right name for a theorem.

view this post on Zulip Patrick Massot (Jun 24 2019 at 18:57):

@Adrian Chu I don't think you're going in the right direction. The first thing to understand is natural numbers are bad. You never noticed because real world always insert coercions to integers and all the coercion related lemmas. My advice is to first state and prove the integer version. Then we'll talk about deducing the evil version. Here is the exercise I propose:

import algebra.euclidean_domain
import tactic.linarith
open euclidean_domain

lemma foo (a b : ) (ha : a  1) (hb : b  1) (h : gcd a b = 1) :
     x y, a*x + 1 = b*y  0  x  0  y :=
begin
  let u := gcd_a a b,
  let v := gcd_b a b,
  let k := max (abs u) (abs v),
  use [-u+b*k, v + a*k],
  repeat { split },
  { rw show 1 = a*u + b*v, from sorry,
    ring },
  { suffices : u  b * max (abs u) (abs v), by linarith,
    -- now you can `calc`
    sorry },
  { sorry }
end

view this post on Zulip Patrick Massot (Jun 24 2019 at 18:58):

each calc block is 4 lines long

view this post on Zulip Patrick Massot (Jun 24 2019 at 18:59):

The first sorry is 20 characters (including spaces)

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:16):

Hmm, do we have any lemma relating nat.gcd and euclidean_domain.gcd?

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:19):

@Johan Commelin maybe?

view this post on Zulip Johan Commelin (Jun 24 2019 at 19:19):

I'm not too familiar with that part of the lib...

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:19):

@Chris Hughes ?

view this post on Zulip Johan Commelin (Jun 24 2019 at 19:20):

I don't know, but I think there is glue between nat.gcd and int.gcd, and then also between int.gcd and euclidean_domain.gcd...

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:20):

Where would that be?

view this post on Zulip Johan Commelin (Jun 24 2019 at 19:21):

Not sure... my memories might be wrong.

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:22):

Going from the int version of Adrian's lemma to the evil version is trivial except for:

a b : ,
h : nat.gcd a b = 1
 gcd a b = 1

view this post on Zulip Johan Commelin (Jun 24 2019 at 19:25):

Hmm... if library_search can't close that, then we probably don't have it.

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:27):

I'm sure British people can prove this

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 19:32):

Maybe show they both have the same universal property? ;-)

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 19:36):

example (a b : ) (h : nat.gcd a b = 1) : int.gcd (a : ) (b : ) = 1 := by rw h; unfold int.gcd; congr'

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 19:38):

example (a b : ) (h : nat.gcd a b = 1) : int.gcd (a : ) (b : ) = 1 := by convert h

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 19:39):

I was slightly surprised this worked until I realised that int.nat_abs (\u m) = m was defeq for m a nat.

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:40):

Nice! This bridges to int.gcd but not to euclidean_domain.gcd

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:49):

and the by convert is useless...

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 19:50):

example (a b : ) (h : nat.gcd a b = 1) : int.gcd (a : ) (b : ) = 1 := h

Oh yeah! I used convert because I "knew" there would be trouble with the cast to int and back.

view this post on Zulip Patrick Massot (Jun 24 2019 at 19:51):

but the game is to use euclidean_domain.gcd

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:00):

#eval euclidean_domain.gcd (-1 : ℤ) (1 : ℤ) -- -1
#eval int.gcd (-1 : ℤ) (1 : ℤ) -- +1

:-(

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:08):

example (a b : ) : int.nat_abs (euclidean_domain.gcd a b) = int.gcd a b :=
begin
  apply gcd.induction a b,
    intro x, rw gcd_zero_left, exact (nat.gcd_zero_left (int.nat_abs x)).symm,
  intros a b ha hab,
  convert hab using 1,
    rw gcd_val a b,
  -- ⊢ int.gcd a b = int.gcd (b % a) a
  sorry
end

This code (thanks, whoever wrote gcd.induction!) reduces the question to int.gcd a b = int.gcd (b % a) a.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:09):

...which is almost a question about nat.gcd apart from the fact that one needs to relate |b%a| to |b|%|a|.

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:13):

What you are doing is not what I asked for

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:13):

why don't you formalise the question?

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:13):

I did!

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:14):

Oh -- I misunderstood the arrows.

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:14):

Going from the int version of Adrian's lemma to the evil version is trivial except for:

a b : ,
h : nat.gcd a b = 1
 gcd a b = 1

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:14):

I thought I did that one.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:14):

I have Lean code which looks like that on my screen right now, with int open :-)

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:14):

You need to open euclidean_domain instead

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:15):

you didn't post a MWE ;-)

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:15):

I did

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:15):

a few messages above

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:15):

anyway

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:15):

It was too minimal -- I guessed you'd opened the wrong thing :-)

I still propose we prove the thing I said about int. You can't use the inductive predicate for euclidean_domain.gcd on nats.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:16):

So unless you want to get your hands dirty, we prove some statement which is valid for all ints (as I was in the middle of doing) and then deduce the nat thing via some dirty work.

view this post on Zulip Patrick Massot (Jun 24 2019 at 20:16):

The context was my first message to Adrian, which included all imports and open

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:17):

And the best statement I could find which was true for all ints was the one I posted.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:20):

bleurgh we need (a b : int), both >=0 implies euclidean_domain.gcd a b >=0 :-/

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:37):

theorem useful (a b : ) : int.nat_abs (b % a) = (int.nat_abs b) % (int.nat_abs a) := sorry

Meh.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:56):

import algebra.euclidean_domain

open euclidean_domain

theorem useful (a b : ) : int.nat_abs (b % a) = (int.nat_abs b) % (int.nat_abs a) := sorry

theorem useful2 (a b : ) : a  0  b  0  euclidean_domain.gcd a b  0 := sorry

theorem abs_gcd_eq_int_gcd (a b : ) : int.nat_abs (euclidean_domain.gcd a b) = int.gcd a b :=
begin
  apply gcd.induction a b,
    intro x, rw gcd_zero_left, exact (nat.gcd_zero_left (int.nat_abs x)).symm,
  intros a b ha hab,
  convert hab using 1,
    rw gcd_val a b,
  --goal now : a ≠ 0 → int.gcd a b = int.gcd (b % a) a -- should be in mathlib
  unfold int.gcd,
  rw useful,
  have h :  x y : , x  0  nat.gcd x y = nat.gcd (y % x) x,
  { intros x y hx,
    cases x with x, revert hx, simp,
    simp -- nat.gcd equation lemma
  },
  have h2 : int.nat_abs a  0 := λ h3, ha (int.eq_zero_of_nat_abs_eq_zero h3), -- missing a trick here
  generalize h3 : int.nat_abs a = A,
  generalize : int.nat_abs b = B,
  apply h, rwa h3,
end

theorem patrick (a b : ) (h : nat.gcd a b = 1) : euclidean_domain.gcd (a : ) b = 1 :=
begin
  show gcd (a : ) b = (1 : ),
  rw h,
  show _ = (int.gcd a b : ),
  rw abs_gcd_eq_int_gcd (a : ) b,
  convert (int.of_nat_nat_abs_eq_of_nonneg _).symm,
  -- ⊢ euclidean_domain.gcd ↑a ↑b ≥ 0
  apply useful2; exact int.of_nat_nonneg _,
end

Two sorries at the top. @Chris Hughes @Mario Carneiro what tricks am I missing?

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 20:56):

The goal is to prove theorem patrick.

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 21:37):

theorem useful2 (a b : ) : a  0  b  0  euclidean_domain.gcd a b  0 :=
begin
  apply gcd.induction a b,
    intros x h hx, rwa gcd_zero_left,
  intros c d hcn h hc hd,
  rw gcd_val,
  apply h _ hc,
  exact int.mod_nonneg d hcn,
end

view this post on Zulip Chris Hughes (Jun 24 2019 at 21:48):

Personally I would question why you want to prove that theorem?

view this post on Zulip Mario Carneiro (Jun 24 2019 at 21:57):

I don't see why euclidean_domain.gcd is getting involved at all if the goal is to prove adrian's original statement

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:17):

Yeah I already tried that but Patrick moaned

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:18):

I'm having trouble working with -A % B with (A B : nat) and int.mod

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:19):

1 goal
B : ℕ,
A : ℕ,
⊢ int.nat_abs (-↑A % ↑B) = int.nat_abs (-↑A) % B

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:34):

That's the last goal but it's bedtime

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:36):

The left mod is int.mod

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:45):

Aargh I don't think some of these are true :-/

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:45):

No wonder I was struggling :-)

view this post on Zulip Kevin Buzzard (Jun 24 2019 at 22:46):

Do we have a tool which checks statements like these for a few random values of the integers in question?

view this post on Zulip Mario Carneiro (Jun 24 2019 at 22:47):

sure, you can use list ops to make a mini quickcheck

view this post on Zulip Mario Carneiro (Jun 24 2019 at 22:49):

#eval do
  A  list.range 10,
  B  list.range 10,
  guard (int.nat_abs (-A % B)  int.nat_abs (-A) % B),
  return (A, B)
-- [(1, 3), ...]

view this post on Zulip Adrian Chu (Jun 25 2019 at 15:14):

Adrian Chu I don't think you're going in the right direction. The first thing to understand is natural numbers are bad. You never noticed because real world always insert coercions to integers and all the coercion related lemmas. My advice is to first state and prove the integer version. Then we'll talk about deducing the evil version. Here is the exercise I propose:

import algebra.euclidean_domain
import tactic.linarith
open euclidean_domain

lemma foo (a b : ) (ha : a  1) (hb : b  1) (h : gcd a b = 1) :
     x y, a*x + 1 = b*y  0  x  0  y :=
begin
  let u := gcd_a a b,
  let v := gcd_b a b,
  let k := max (abs u) (abs v),
  use [-u+b*k, v + a*k],
  repeat { split },
  { rw show 1 = a*u + b*v, from sorry,
    ring },
  { suffices : u  b * max (abs u) (abs v), by linarith,
    -- now you can `calc`
    sorry },
  { sorry }
end

So i guess i should try finishing this version of my lemma, and forget everything about nat.gcd

view this post on Zulip Patrick Massot (Jun 25 2019 at 15:17):

If you can afford that then of course everything becomes much easier. I still think it's a problem that mathlib has at least three gcd with no lemmas relating them in the case of integers

view this post on Zulip Patrick Massot (Jun 25 2019 at 15:17):

Did you manage to fill in the sorries in my exercise?

view this post on Zulip Adrian Chu (Jun 25 2019 at 15:18):

I am working on them now

view this post on Zulip Patrick Massot (Jun 25 2019 at 15:20):

Ok, I hope I inserted them wisely. I first wrote the full proof and then removed it to help you getting better training. Don't hesitate to ask questions if it's still too painful

view this post on Zulip Adrian Chu (Jun 25 2019 at 15:50):

import algebra.euclidean_domain
import tactic.linarith tactic.library_search
open euclidean_domain

lemma foo (a b : ) (ha : a  1) (hb : b  1) (h : gcd a b = 1) :
     x y, a*x + 1 = b*y  0  x  0  y :=
begin
  let u := gcd_a a b,
  let v := gcd_b a b,
  let k := max (abs u) (abs v),
  have hk : 0  k :=
    calc 0  abs u : abs_nonneg u
    ...  max (abs u) (abs v) : le_max_left (abs u) (abs v)
    ... = k : by simp,
  use [-u+b*k, v + a*k],
  repeat { split },
  { rw show 1 = a*u + b*v, from sorry,
    ring },
  { suffices : u  b * max (abs u) (abs v), by linarith,
    calc u  abs u : by exact le_max_left u (-u)
    ...  max (abs u) (abs v) : le_max_left (abs u) (abs v)
    ... = 1 * max (abs u) (abs v) : by simp
    ...  b * max (abs u) (abs v) : by exact mul_le_mul_of_nonneg_right hb hk },
  { suffices : -v  a * max (abs u) (abs v), by linarith,
    calc -v  abs (-v) : by exact le_max_left (-v) (-(-v))
    ... = abs v : abs_neg v
    ...  max (abs u) (abs v) : le_max_right (abs u) (abs v)
    ... = 1 * max (abs u) (abs v) : by simp
    ...  a * max (abs u) (abs v) : by exact mul_le_mul_of_nonneg_right ha hk}
end

view this post on Zulip Adrian Chu (Jun 25 2019 at 15:50):

I'm not able to figure out the first sorry (with 20 characters only). i know we need to use gcd_eq_gcd_ab @Patrick Massot

view this post on Zulip Adrian Chu (Jun 25 2019 at 15:55):

Personally I would question why you want to prove that theorem?

This is a crucial lemma in a theorem i want to prove

view this post on Zulip Kevin Buzzard (Jun 25 2019 at 15:57):

Personally I would question why you want to prove that theorem?

This is a crucial lemma in a theorem i want to prove

I think that "that theorem" might have referred to the compatibility of the various notions of gcd which we have in Lean.

view this post on Zulip Patrick Massot (Jun 25 2019 at 16:06):

You can shorten your first calc block to

calc 0  abs u : abs_nonneg u
      ...  _ : le_max_left _ _

(or of course you can say have hk : 0 ≤ k, from le_trans (abs_nonneg u) (le_max_left _ _),)

view this post on Zulip Patrick Massot (Jun 25 2019 at 16:06):

The sorry you couldn't do is h ▸ gcd_eq_gcd_ab a b

view this post on Zulip Patrick Massot (Jun 25 2019 at 16:07):

I hope you've learn a couple of tricks (those are no so easy to document)

view this post on Zulip Adrian Chu (Jun 25 2019 at 16:09):

wow thanks a lot!

view this post on Zulip Adrian Chu (Jun 25 2019 at 16:09):

i can finally move one to the second lemma, and then my main theorem :)

view this post on Zulip Kevin Buzzard (Jun 25 2019 at 16:09):

The triangle is term mode's version of the rewrite tactic.

view this post on Zulip Adrian Chu (Jun 25 2019 at 16:53):

import algebra.euclidean_domain algebra.big_operators data.finset

open euclidean_domain

def fin_n_to_list {n : } (x: fin n  ) : list  :=
  (list.range n).map (λ i, if h : i < n then x i, h else 0)

def n_lcm {n : } (x : fin n  ) :  :=
  list.foldl lcm 1 (fin_n_to_list x)

lemma n_lcm_coprime {n : } (x : fin n  ) (y : )
  (hx :  i : fin n, 1  x i) (hy : 1  y)
  (coprime :  i : fin n, gcd (x i) y = 1) :
  gcd (n_lcm x) y = 1 :=
sorry

view this post on Zulip Adrian Chu (Jun 25 2019 at 16:54):

i will start to prove this lemma. is my formulation of definitions and the statement of lemma appropriate?

view this post on Zulip Kevin Buzzard (Jun 25 2019 at 17:07):

Why are you using maps fin n -> int at all? You are carrying around the length of your list, but you could just read it off by looking at the length of the list.

view this post on Zulip Kevin Buzzard (Jun 25 2019 at 17:13):

import algebra.euclidean_domain algebra.big_operators data.finset

open euclidean_domain

def list.lcm (x : list ) :  :=
  list.foldl lcm 1 x

lemma list.lcm_coprime (x : list ) (y : )
  (hx :  s  x, (1 : )  s) (hy : 1  y)
  (coprime :  s  x, gcd s y = 1) :
  gcd (x.lcm) y = 1 :=
sorry

No n in sight -- it's never needed.

view this post on Zulip Kevin Buzzard (Jun 25 2019 at 17:14):

Note also x.lcm for list.lcm x, it's a cool thing which I only recently understood.

view this post on Zulip Kevin Buzzard (Jun 25 2019 at 17:15):

The CS purists might even say that these should all be theorems about multisets not lists, because the lcm does not depend on the order, so why are you carrying that around?

view this post on Zulip Adrian Chu (Jun 26 2019 at 04:04):

a naive question: can a list have infinite length?

view this post on Zulip Mario Carneiro (Jun 26 2019 at 04:13):

No

view this post on Zulip Johan Commelin (Jun 26 2019 at 04:16):

Nope, they can not.

view this post on Zulip Johan Commelin (Jun 26 2019 at 04:16):

list.length is defined for all lists, and it is a function to nat.

view this post on Zulip Johan Commelin (Jun 26 2019 at 04:16):

Infinite lists are usually called "streams", and they need a different implementation. Not sure if we have them in Lean.

view this post on Zulip Johan Commelin (Jun 26 2019 at 04:16):

Sorry... laggy internet connection...

view this post on Zulip Mario Carneiro (Jun 26 2019 at 04:20):

we have streams, they are just defined as stream A := nat -> A

view this post on Zulip Adrian Chu (Jun 26 2019 at 04:21):

i see. all I want is an n-tuple of numbers. so i will use list Z instead of fin n -> Z.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 04:21):

There are also lazy lists, which are more like haskell lists in implementation but are still finite according to the theory. But in meta land you can construct infinite lazy lists

view this post on Zulip Johan Commelin (Jun 26 2019 at 04:22):

i see. all I want is an n-tuple of numbers. so i will use list Z instead of fin n -> Z.

The question is... is your n fixed? Because with a list, you don't know if it has length n.

view this post on Zulip Adrian Chu (Jun 26 2019 at 04:25):

no, the lemma (and my main theorem) just need an arbitrary finite number of positive integers as inputs.

view this post on Zulip Adrian Chu (Jun 26 2019 at 04:26):

so list should be good

view this post on Zulip Adrian Chu (Jun 26 2019 at 04:48):

i just realized a problem. in my main theorem, i have a statement involving a^b, where a and b are positive integers. but since we are now letting a, b be int instead of nat, i cant use the default a^b function

view this post on Zulip Adrian Chu (Jun 26 2019 at 04:53):

well i can use (nat_abs a)^(nat_abs b). its a bit ugly, but nvm

view this post on Zulip Mario Carneiro (Jun 26 2019 at 05:13):

I think you should keep them as nats rather than do something like that

view this post on Zulip Mario Carneiro (Jun 26 2019 at 05:13):

if they are actually nats then there's nothing wrong with that

view this post on Zulip Johan Commelin (Jun 26 2019 at 05:28):

@Adrian Chu You can let a and b be nats but nevertheless use int.gcd instead of nat.gcd.

view this post on Zulip Johan Commelin (Jun 26 2019 at 05:28):

I agree that it's quite messy.

view this post on Zulip Adrian Chu (Jun 26 2019 at 05:45):

Adrian Chu You can let a and b be nats but nevertheless use int.gcd instead of nat.gcd.

I don't think we can, since this gives error:

theorem mythm (r : list ) (s : ) (hr :  z  r, 1  z) (hs : 1  s)
  (coprime :  z  r, int.gcd z s = 1) : 1 = 1 := sorry

view this post on Zulip Mario Carneiro (Jun 26 2019 at 05:47):

what error? You may need to put some up arrows in there

view this post on Zulip Adrian Chu (Jun 26 2019 at 05:49):

OK, fixed

view this post on Zulip Adrian Chu (Jun 26 2019 at 06:01):

let x : list nat and I want to sum it. if for some reason I want to use finset.univ.sum instead of x.sum, what is the correct syntax?

view this post on Zulip Adrian Chu (Jun 26 2019 at 06:04):

import data.fintype

variable x : list 
#check finset.univ.sum (λ i, x.nth i)
#check finset.univ.sum (λ i : fin x.range, x.nth i)

this doesnt work

view this post on Zulip Johan Commelin (Jun 26 2019 at 06:05):

You need to range of the length of the list.

view this post on Zulip Johan Commelin (Jun 26 2019 at 06:05):

Why do you want to use finset.sum?

view this post on Zulip Johan Commelin (Jun 26 2019 at 06:05):

If so... shouldn't you be using finset nat instead of list nat?

view this post on Zulip Adrian Chu (Jun 26 2019 at 06:09):

well I have x : list nat and r : list nat, lists of positive integers of the same length, and i want to sum (i-th term of x)^(i-th term of r) over i

view this post on Zulip Adrian Chu (Jun 26 2019 at 06:09):

i thought using finset.univ.sum is the easiest

view this post on Zulip Mario Carneiro (Jun 26 2019 at 06:10):

I would do something like zip_with to put the powers together and list.sum to add them up

view this post on Zulip Johan Commelin (Jun 26 2019 at 06:10):

well I have x : list nat and r : list nat, lists of positive integers of the same length, and i want to sum (i-th term of x)^(i-th term of r) over i

??? why are they of the same length?

view this post on Zulip Adrian Chu (Jun 26 2019 at 06:11):

well I have x : list nat and r : list nat, lists of positive integers of the same length, and i want to sum (i-th term of x)^(i-th term of r) over i

??? why are they of the same length?

by assumption

view this post on Zulip Scott Morrison (Jun 26 2019 at 07:13):

Can you arrange to have a list (nat x nat)?

view this post on Zulip Adrian Chu (Jun 26 2019 at 07:29):

Can you arrange to have a list (nat x nat)?

how will this help?

view this post on Zulip Marc Huisinga (Jun 26 2019 at 07:31):

it ensures that you have two lists of the same size, but is this really the easiest way to do it? why not pass a proof that the lengths are equal instead?

view this post on Zulip Mario Carneiro (Jun 26 2019 at 07:31):

it separates the information somewhat and generally makes the proofs harder

view this post on Zulip Mario Carneiro (Jun 26 2019 at 07:32):

I don't know about the direction of this thread though. What is the actual goal? I think the encoding decisions are being made without a good idea of the target theorem and that's bad news

view this post on Zulip Adrian Chu (Jun 26 2019 at 07:33):

okok, let me write out the complete thm

view this post on Zulip Adrian Chu (Jun 26 2019 at 07:37):

import data.fintype

theorem mythm (n : ) (r : fin n  ) (s : ) (hr :  i, 1  r i) (hs : 1  s)
  (coprime :  i : fin n, nat.coprime (r i) s) :
   x : fin n  ,  y : ,
  ( i, 1  x i)  (0  y)  (finset.univ.sum (λ i, (x i)^(r i)) = y^s) :=
sorry

view this post on Zulip Adrian Chu (Jun 26 2019 at 07:37):

this is the original form of my theorem

view this post on Zulip Adrian Chu (Jun 26 2019 at 07:38):

and we can discuss whether (1) to use nat or int, and (2) to use fin n -> nat or list nat

view this post on Zulip Marc Huisinga (Jun 26 2019 at 07:40):

the only adv of fin n -> nat i can think of is that fin n -> nat can be handy when dealing with nested inductive types

view this post on Zulip Adrian Chu (Jun 26 2019 at 07:43):

and I will use these 2 lemmas

import data.fintype
import algebra.euclidean_domain
import algebra.big_operators

open euclidean_domain

def fin_n_to_list {n : } (x: fin n  ) : list  :=
  (list.range n).map (λ i, if h : i < n then x i, h else 0)

def n_lcm {n : } (x : fin n  ) :  :=
  list.foldl nat.lcm 1 (fin_n_to_list x)

lemma n_lcm_coprime {n : } (x : fin n  ) (y : )
  (coprime :  i : fin n, nat.coprime (x i) y) :
  nat.coprime (n_lcm x) y := sorry -- not yet proven

lemma bazout (a b : ) (ha : a  1) (hb : b  1) (h : gcd a b = 1) :
     x y, a*x + 1 = b*y  0  x  0  y := sorry -- already proven

view this post on Zulip Mario Carneiro (Jun 26 2019 at 07:47):

The statement of mythm looks fine, except that you can replace fin n with any fintype A, and the 0 <= y is redundant

view this post on Zulip Adrian Chu (Jun 26 2019 at 09:58):

no... i just tried, the conversion between int and nat is so frustrating (since my bazout lemma is using int). i want to use int in mythm. do we have a^b for a, b in int ?

view this post on Zulip Mario Carneiro (Jun 26 2019 at 10:02):

You want to have your bezout lemma on nat too

view this post on Zulip Adrian Chu (Jun 26 2019 at 10:13):

good idea, i can make a new lemma bazout2 for nat using bazout

view this post on Zulip Adrian Chu (Jun 26 2019 at 10:22):

my strategy now is to use a, b : nat, but use euclidean_domain.gcd (a:int) b

view this post on Zulip Mario Carneiro (Jun 26 2019 at 10:30):

Since you seem to already have a solution, I will show you how I would have proven your original bezout theorem:

lemma bezout (a : ) (b : ) (ha : a  1) (hb : b  1) (h : nat.gcd a b = 1) :
     x : ,  y : , a*x + 1 = b*y :=
begin
  let k := max (int.nat_abs (nat.gcd_a a b)) (int.nat_abs (nat.gcd_b a b)) + 1,
  let x :  := b*k - nat.gcd_a a b,
  let y :  := a*k + nat.gcd_b a b,
  refine int.to_nat x, int.to_nat y, int.coe_nat_inj _⟩,
  suffices : (a * int.to_nat x + 1 : ) = b * int.to_nat y, {simpa},
  have k1 : 1  k := nat.le_add_left _ _,
  have ha' : (1:)  a := int.coe_nat_le.2 ha,
  have hb' : (1:)  b := int.coe_nat_le.2 hb,
  have x0 : 0  x,
  { refine sub_nonneg.2 _,
    have := mul_le_mul_of_nonneg_right hb' (int.coe_nat_nonneg k),
    rw one_mul at this,
    refine le_trans (le_trans int.le_nat_abs _) this,
    refine int.coe_nat_le.2 _,
    exact nat.le_succ_of_le (le_max_left _ _) },
  have y0 : 0  y,
  { refine sub_le_iff_le_add.1 _,
    rw zero_sub,
    have := mul_le_mul_of_nonneg_right ha' (int.coe_nat_nonneg k),
    rw one_mul at this,
    refine le_trans (le_trans int.le_nat_abs _) this,
    rw [int.nat_abs_neg, int.coe_nat_le],
    exact nat.le_succ_of_le (le_max_right _ _) },
  rw [int.to_nat_of_nonneg x0, int.to_nat_of_nonneg y0],
  have := nat.gcd_eq_gcd_ab a b,
  rw [h, int.coe_nat_one] at this,
  rw [this, mul_sub,  add_assoc, sub_add_cancel, mul_left_comm,  mul_add],
end

I don't think it's necessary to ban the use of nats as long as you are conscientious in your use of the up arrow. In particular if it makes you use more unusual functions with a worse interface then it's not worth it

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:00):

I think this is completely crazy. How can it be a good idea to have nat.gcd, int.gcd and euclidean_domain.gcd and not a single lemma relating those?

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:00):

Of course there should be such lemmas

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:01):

but we don't need the other gcds for this theorem

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:02):

The proof of this theorem is much nicer with euclidean_domain.gcd. Your proof is hideous, even if it could be nicer using norm_cast

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:02):

None of the proof has to do with gcd

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:03):

It's quite possible that norm_cast can be used in a few places, but it's mostly about dealing with max and simple algebra

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:03):

also I don't really care about calc blocks

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:05):

Are you saying that there is a completely different proof that uses euclidean_domain.gcd with some different lemmas about it? I'm mostly following adrian's proof sketch here

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:06):

The fact that we have

theorem gcd_eq_gcd_ab : (gcd a b : ) = a * gcd_a a b + b * gcd_b a b := ...

and this proof is still nearly 30 lines is what is so jarring.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:06):

This theorem is proving something completely different

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:06):

Hmm, I guess gcd_a is probably an int, so there's some content getting all the signs right

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:07):

The important part is the fact that you can shift around solutions by a multiple

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:07):

Right.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:07):

and then you have some inequalities to check

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:07):

I mean

lemma foo (a b : ) (ha : a  1) (hb : b  1) (h : gcd a b = 1) :
     x y, a*x + 1 = b*y  0  x  0  y :=
begin
  let u := gcd_a a b,
  let v := gcd_b a b,
  let k := max (abs u) (abs v),
  have hk : 0  k := le_trans (abs_nonneg u) (le_max_left _ _),
  use [-u+b*k, v + a*k],
  repeat { split },
  { rw show 1 = a*u + b*v, from h  gcd_eq_gcd_ab a b,
    ring },
  { suffices : u  b * max (abs u) (abs v), by linarith,
    calc u  abs u : le_abs_self u
    ...  max (abs u) (abs v) : le_max_left _ _
    ... = 1*max (abs u) (abs v) : by simp
    ...  b*max (abs u) (abs v) : mul_le_mul_of_nonneg_right hb hk },
  { suffices : -v  a * max (abs u) (abs v), by linarith,
    calc -v  abs v : neg_le_abs_self _
    ...  max (abs u) (abs v) : le_max_right _ _
    ... = 1*max (abs u) (abs v) : by simp [le_max_right ]
    ...  a*max (abs u) (abs v) : mul_le_mul_of_nonneg_right ha hk }
end

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:08):

I think our views on the meaning of the phrase "completely different" might have diverged a bit but I do take your point that more needs to be said.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:08):

Ah, you linarith'd

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:08):

And then, modulo relating different versions of gcd, the proof of the nat version is:

lemma baz (a : ) (b : ) (ha : a  1) (hb : b  1) (h : nat.gcd a b = 1) :
     x : ,  y : , a*x + 1 = b*y :=
begin
  rcases foo a b (by exact_mod_cast ha) (by exact_mod_cast hb) sorry with x, y, h, hx, hy,
  use [x.to_nat, y.to_nat],
  rw [show x = (x.to_nat : ), by simp [hx],
      show y = (y.to_nat : ), by simp [hy]] at h,
  exact_mod_cast h
end

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:08):

and he rung.

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:10):

Of course I linarith, I ring, and norm_cast. I very strongly believe all this is essential for the future of proof assistants for mathematicians

view this post on Zulip Adrian Chu (Jun 26 2019 at 11:15):

million thanks. i am building up the framework of the proof of mythm currently.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:27):

It's quite possible that norm_cast can be used in a few places, but it's mostly about dealing with max and simple algebra

This is just the metamath-mario trying to get out. You can see a proof from very low-level principles and so figure that this is a good way to do it. The mathematicians see the theorem for int and figure that the boring work is already done, and that we should just use that.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:29):

I don't use a high level tactic until I understand very well how effective it is and in what circumstances it can be used. AKA "no magic"

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:30):

That's exactly what I'm saying. You were brought up on metamath and this has formed the way you think about how to solve goals.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:30):

That said there are also a few proof tricks in Patrick's proof that I missed

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:30):

We need both. We need Mario on one side, and we need Rob and Paul-Nicolas (and hopefully many more) on the other side

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:31):

Yes absolutely. I'm just saying that it's interesting.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:32):

I think Mario wrote ring ;-)

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:33):

The difference between us is I feel the pressure of the actual proof term at all times

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:33):

If I use a complicated tactic that spews some gigantic... thing... in for my proof, I think it's a long and ugly proof

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:33):

That's an interesting comment. I have no concept of what proof terms look like.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:33):

even if the proof script is just by magic

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:34):

When I use refine and apply and rw, I know exactly what proof term is getting generated and how heavy that's going to be for the kernel

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:35):

With Olympiad training as a kid I was taught the importance of getting the solution out as quickly as possible, who cares about other stuff like elegance.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:35):

I'm hoping that refine and apply don't add too much weight to the proof term! I know how to do them in term mode :-)

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:35):

that's exactly the point

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:36):

Then we need more CS people working on the magic tactics, so that they produce nicer terms

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:36):

You don't really need them - you could do them in term mode. They are just slight shorthands for building that proof term

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:37):

why do I care about the size of a proof term? It's immediately forgotten.

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:37):

I wish that was a bigger concern in lean-land. I care about it very much, but lean fights me when it comes to proof optimization

view this post on Zulip Mario Carneiro (Jun 26 2019 at 11:37):

It's not forgotten, it's stored and passed around and checked hundreds of time on travis and burns many CPU hours around the world

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:45):

I'm seriously thinking about buying a bigger CPU tonight

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:46):

I think I want more cores and more RAM, right?

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:46):

gone are the days of more pixels. I remember wanting more colours once!

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:46):

I upgraded from 2 to 8

view this post on Zulip Reid Barton (Jun 26 2019 at 11:47):

But some of the 8 colors were different on every other pixel so it was really more like... 12

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:47):

I think VScode doesn't use much more than 8 colors, so you should be fine now. Let's go for CPU cores instead

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:47):

Is a GPU of any use?

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:47):

Unfortunately no

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:48):

But wait until @Gabriel Ebner starts working on Lean 4 on GPU

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:51):

This isn't really a noob question and probably deserves its own thread. My laptop has something like 4 cores and 16 gigs of ram and even if I compile mathlib I don't ever get close to those 16 gigs.

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:51):

I have RAM problems when I want to compile mathlib while using VScode on some other project

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:52):

In particular, I wonder whether somehow there's a theorem of the form "if you have x cores, then don't buy any more than c * x gigs of ram because Lean won't use that much" for some constant c.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:53):

When I want to compile mathlib and do something else too, I see how much free ram I have and then compile from the command line with the -M flag. Occasionally the build just runs out of memory and stops, and then I just start it again.

view this post on Zulip Johan Commelin (Jun 26 2019 at 11:54):

I haven't compile mathlib in the last 6 weeks. cache-olean is quite awesome.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:54):

Using the M flag also stopped my desktop (which had no swap) from randomly crashing when Lean suddenly goes beserk and fills up all memory.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 11:55):

IIRC it still didn't stop Lean going crazy when invoked via VS Code, so I added some swap anyway.

view this post on Zulip Patrick Massot (Jun 26 2019 at 11:55):

compiling mathlib is still required when working on mathlib

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 12:56):

It's not forgotten, it's stored and passed around and checked hundreds of time on travis and burns many CPU hours around the world

You make it sound like I'm responsible for climate change!

view this post on Zulip Patrick Massot (Jun 26 2019 at 12:57):

This is clearly what he means.

view this post on Zulip Patrick Massot (Jun 26 2019 at 12:57):

And now you'll make it worse by flying to Portland

view this post on Zulip Adrian Chu (Jun 26 2019 at 14:49):

import algebra.euclidean_domain data.vector
import tactic.linarith tactic.library_search algebra.big_operators data.fintype
import data.finset data.nat.basic

open euclidean_domain

def fin_n_to_list {n : } (x: fin n  ) : list  :=
  (list.range n).map (λ i, if h : i < n then x i, h else 0)

def n_lcm {n : } (x : fin n  ) :  :=
  list.foldl nat.lcm 1 (fin_n_to_list x)

lemma sum_to_mul (a b : ):  finset.univ.sum (λ i : fin a, b) = a*b :=
by simp [finset.sum_const, finset.card_univ, fintype.card_fin]

lemma n_lcm_coprime {n : } (x : fin n  ) (y : )
  (coprime :  i : fin n, nat.gcd (x i) y = 1) :
  nat.gcd (n_lcm x) y = 1 :=
sorry -- need to prove

lemma bazout_int (a b : ) (ha : a  1) (hb : b  1) (h : gcd a b = 1) :
     x : ,  y : , a*x + 1 = b*y  0  x  0  y :=
sorry -- already proven

lemma bazout_nat (a b : ) (ha : a  1) (hb : b  1) (h : nat.gcd a b = 1) :
  -- this is Patrick's version, or we can use mario's version above
     x : ,  y : , a*x + 1 = b*y :=
begin
  rcases bazout_int a b (by exact_mod_cast ha) (by exact_mod_cast hb) sorry with x, y, h, hx, hy,
-- need to prove
  use [x.to_nat, y.to_nat],
  rw [show x = (x.to_nat : ), by simp [hx],
      show y = (y.to_nat : ), by simp [hy]] at h,
  exact_mod_cast h
end

theorem mythm (n : ) (r : fin n  ) (s : )
    (hn  1) (hr :  i, r i  1) (hs : s  1)
    (coprime :  i : fin n, nat.gcd (r i) s = 1) :
     x : fin n  ,  y : ,
    ( i, x i  1)  (finset.univ.sum (λ i, (x i)^(r i)) = y^s) :=
begin
    let t := n_lcm r,
    have t_geq_1 : t  1 := sorry,  -- need to prove
    have ri_div_t : ( i : fin n, t % (r i) = 0) := sorry,  -- need to prove
    let t_s_coprime := n_lcm_coprime r s coprime,
    cases (bazout_nat t s t_geq_1 hs t_s_coprime) with a ha,
    cases ha with b hab,
    let x := λ i : fin n, n^((a*t)/r i),
    let y := n^b,
    have trivial1 : a*t + 1 = t*a + 1 := by simp [mul_comm],
    fapply exists.intro,
    exact x,
    fapply exists.intro,
    exact y,
    repeat {split},
    {intro i, sorry}, -- for all i xi ≥ 1
    calc finset.univ.sum (λ i, (n^((a*t)/r i))^(r i))
    = finset.univ.sum (λ i, (n^(((a*t)/r i)*(r i)))) : by sorry
    ... = finset.univ.sum (λ i: fin n, n^(a*t)) : by sorry
    ... = n*(n^(a*t)) : sum_to_mul n (n^(a*t))
    ... = n^(a*t + 1): by exact mul_comm n (n^(a*t))
    ... = n^(t*a + 1) : by exact congr_arg (pow n) trivial1
    ... = n^(s*b) : by exact congr_arg (pow n) hab
    ... = n^(b*s) : by exact congr_arg (pow n) (mul_comm s b)
    ... = (n^b)^s : nat.pow_mul b s n
end

view this post on Zulip Adrian Chu (Jun 26 2019 at 14:50):

this is a record of my (our) progress, i am (we are) getting closer! but for me it's time to rest

view this post on Zulip Reid Barton (Jun 26 2019 at 14:54):

I know Lean doesn't care, but the name is bezout (or even better, Bézout)

view this post on Zulip Johan Commelin (Jun 26 2019 at 14:55):

I'm inclined to say baz… (oh, well, never mind…)

view this post on Zulip Patrick Massot (Jun 26 2019 at 15:25):

I assumed all along this was an intentional reference to the foo, bar, baz sequence, being a variation on Bézout

view this post on Zulip Patrick Massot (Jun 26 2019 at 15:26):

but maybe I was wrong and Adrian wants to also credit Bachet

view this post on Zulip Kevin Kappelmann (Jun 26 2019 at 19:14):

When using induction t : e, I get a weird inductive hypothesis. For example,

example {n : } : n  n * n :=
begin
induction n_eq : n with m IH,
{ simp },
{ sorry } -- ill-formed IH here
end

will create a goal

case nat.succ
n m : ,
IH : n = m  m  m * m,
n_eq : n = nat.succ m
 nat.succ m  nat.succ m * nat.succ m

but clearly, n ≠ m so I cannot use the IH for my proof. Am I doing something wrong? Note: I need n_eq in the theorem I am actually proving, so just dropping n_eq : is not an option.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:20):

What does "I need n_eq in the theorem I am actually proving" mean? What's wrong with just induction n with m IH?

view this post on Zulip Johan Commelin (Jun 26 2019 at 19:21):

Wrong thread?

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:21):

(deleted)

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:22):

What does "I need n_eq in the theorem I am actually proving" mean? What's wrong with just induction n with m IH?

I mean, what hypothesis do you actually want, if it's not what you got?

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:27):

But yeah something is weird there. It's as if induction n_eq : n will always cause you trouble.

view this post on Zulip Kevin Kappelmann (Jun 26 2019 at 19:27):

That was ill-phrased, let me clarify. I did not want to say that I need n_eq, but rather, I still want to be able to refer to n in both cases. Basically, I want to do some work for both case nat.zero and nat.succ using all_goals and referring to n like this:

example {n : } : n  n * n :=
begin
induction n_eq : n with m IH,
all_goals {
  have : 0  n, from n.zero_le
},
{ simp },
{ sorry }
end

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:28):

But when you do induction n, doesn't n literally disappear from the context?

view this post on Zulip Kevin Kappelmann (Jun 26 2019 at 19:28):

Yep, that's what I want to avoid!

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:29):

But isn't that how induction works?

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:29):

I see what you're trying to do.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:29):

Why don't you just do what you want to do with n before you start on the induction?

view this post on Zulip Kevin Kappelmann (Jun 26 2019 at 19:32):

Because then it introduces these statements as premises in my IH as well. Cf:

example {n : } : n  n * n :=
begin
have : 0  n, from n.zero_le,
induction n with m IH,
{ simp },
{ sorry } -- check IH here
end

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:32):

Yes you're right.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:34):

It's just reverting all hypotheses with an n in before starting the induction.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:35):

example {n : } : n  n * n :=
begin
have : 0  n, from n.zero_le,
apply nat.rec_on n,

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:35):

It must just be what the tactic does.

view this post on Zulip Reid Barton (Jun 26 2019 at 19:35):

I think you can use set to rename succ m to n if you like

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:35):

You can get round it by just applying the recursor directly like in the above.

view this post on Zulip Chris Hughes (Jun 26 2019 at 19:36):

I think you want to prove something like forall t > 0, n \le n * t

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:36):

No, my idea doesn't work either.

view this post on Zulip Chris Hughes (Jun 26 2019 at 19:36):

And then apply it to n, and prove the case n =0 separately

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:37):

Chris the question is how to get induction not to revert facts about n which you want left alone.

view this post on Zulip Chris Hughes (Jun 26 2019 at 19:37):

clear first

view this post on Zulip Reid Barton (Jun 26 2019 at 19:38):

Oh I guess I didn't really understand what you are trying to do

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:38):

The question is how to get from

1 goal
n : ℕ,
this : 0 ≤ n
⊢ n ≤ n * n

to

2 goals
case nat.zero
this : 0 ≤ 0
⊢ 0 ≤ 0 * 0

case nat.succ
m : ℕ,
IH : m ≤ m * m,
this : 0 ≤ nat.succ m
⊢ nat.succ m ≤ nat.succ m * nat.succ m

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:39):

i.e. "do cases on this but do induction on the goal"

view this post on Zulip Chris Hughes (Jun 26 2019 at 19:41):

In general that's impossible, because if it didn't put the hypothesis at the start you could prove contradictions right. Unless I misunderstand.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:41):

induction n with m IH gives

case nat.succ
m : ℕ,
IH : 0 ≤ m → m ≤ m * m,
this : 0 ≤ nat.succ m
⊢ nat.succ m ≤ nat.succ m * nat.succ m

and induction h : n with m IH gives

case nat.succ
n : ℕ,
this : 0 ≤ n,
m : ℕ,
IH : n = m → m ≤ m * m,
h : n = nat.succ m
⊢ nat.succ m ≤ nat.succ m * nat.succ m

In both cases the inductive hypothesis is rendered useless because the assumption is false.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:41):

You might be right that it's impossible.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:43):

@Kevin Kappelmann That n really does not exist any more. This is the problem. If you have a statement which is true for all all nats, then don't prove it for n, prove it for all nats before the induction starts and then apply it to whatever you want to apply it to afterwards.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:43):

I think it's misleading to think that the n has "become succ m" in the inductive step. The n is meaningfully attached to both m and succ m here.

view this post on Zulip Chris Hughes (Jun 26 2019 at 19:52):

Here's a contradiction I can prove

open nat
lemma rubbish (n m : ) (h : n = m) (hm : m  1) : n = 0  n > m :=
begin
  induction n,
  { left, refl },
  { -- case nat.succ
    -- m : ℕ,
    -- hm : m ≠ 1,
    -- n_n : ℕ,
    -- n_ih : n_n = m → n_n = 0 ∨ n_n > m,
    -- h : succ n_n = m
    -- ⊢ succ n_n = 0 ∨ succ n_n > m
    have : n_n = 0  n_n > m, from sorry,
    cases this,
    subst this, exfalso,
    exact hm h.symm,
    exact or.inr (lt_succ_of_lt this) }
end

example : false := absurd (rubbish 2 2) dec_trivial

view this post on Zulip Kevin Kappelmann (Jun 26 2019 at 19:54):

Alright, thanks. Using induction with this pattern induction t : e is pretty useless then, isn't it?

view this post on Zulip Chris Hughes (Jun 26 2019 at 19:57):

Maybe for naturals. There are definitely some uses, but I can't think of any right now.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:58):

cases t : e is surely useful.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 19:59):

But when it really is an induction, won't the inductive hypothesis end up contradicting another hypothesis most of the time?

view this post on Zulip Chris Hughes (Jun 26 2019 at 20:00):

I think all of the time, given the freely generated nature of inductive types.

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 20:00):

Yeah, I'm just trying to prove list.rec with induction h : l and I don't think it can be done.

view this post on Zulip Chris Hughes (Jun 26 2019 at 20:01):

Maybe it would be useful for custom recursors when you do induction ... using ...

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 20:03):

-- attempt to prove list.rec
example : Π {T : Type} {C : list T  Type},
    C list.nil  (Π (hd : T) (tl : list T), C tl  C (hd :: tl))  Π (n : list T), C n :=
begin
  intros T C hnil hcons l,
  induction h : l,
    exact hnil,
  apply hcons,
  apply ih,
  -- dead
  sorry
end

view this post on Zulip Reid Barton (Jun 26 2019 at 20:05):

mathlib has a fair number of uses (git grep '\binduction .*:') but I didn't check whether they could be replaced by cases

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 20:20):

Or just search \binduction .*: in VS Code but switch on the .* option (use regular expression)

view this post on Zulip Kevin Buzzard (Jun 26 2019 at 20:23):

All the ones I checked, could be replaced by cases. There are loads in data/seq and I didn't check any of them.

view this post on Zulip Scott Viteri (Jun 27 2019 at 02:12):

Hello,
Upon adding mathlib as a project dependency, searching for definitions with emacs helm errors out due to excessive memory consumption. I don't see any mentions of this in github lean-mode issues. Is this to be expected?
Thanks,
Scott

view this post on Zulip Reid Barton (Jun 27 2019 at 02:16):

Running leanpkg build in your project should help

view this post on Zulip Reid Barton (Jun 27 2019 at 02:16):

That will build whatever parts of mathlib your project currently imports, so that later lean won't have to compile them on the fly

view this post on Zulip Reid Barton (Jun 27 2019 at 02:17):

If you just want to build all of mathlib, I think lean --make _target/deps/mathlib/src should work

view this post on Zulip Scott Viteri (Jun 27 2019 at 02:20):

I see -- I tried 'leanpkg build' and and still getting memory issues. I'll try building all of mathlib.

view this post on Zulip Reid Barton (Jun 27 2019 at 02:21):

You might need to restart the lean server after running leanpkg build as well

view this post on Zulip Reid Barton (Jun 27 2019 at 02:22):

My brain isn't in Lean mode so I forget the key

view this post on Zulip Scott Viteri (Jun 27 2019 at 02:22):

Oh, that did it

view this post on Zulip Scott Viteri (Jun 27 2019 at 02:22):

C-c C-r

view this post on Zulip Scott Viteri (Jun 27 2019 at 02:23):

Wonderful, thank you

view this post on Zulip Scott Viteri (Jun 27 2019 at 02:24):

My brain isn't in Lean mode so I forget the key

If only brains could context switch with a simple M-x ...

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:25):

Separate question -- is there a general rule of thumb of when to use the tactic mode for proofs?

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:25):

Or is it just a stylistic choice

view this post on Zulip Mario Carneiro (Jun 27 2019 at 04:26):

when it's easier

view this post on Zulip Mario Carneiro (Jun 27 2019 at 04:27):

or more compact

view this post on Zulip Mario Carneiro (Jun 27 2019 at 04:27):

The best approach is to use a combination of both and be comfortable going back and forth

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:30):

is going from regular to tactic mode using "by"?

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:31):

and is the opposite direction using exact?

view this post on Zulip Mario Carneiro (Jun 27 2019 at 04:32):

yes

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:34):

yes to both directions?

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:36):

Also I didn't realize a bit ago that you can use start begin end blocks in the middle of a proof

view this post on Zulip Scott Morrison (Jun 27 2019 at 04:40):

I find that for "easy" stuff (i.e. proofs that you know ought to be easy, so you don't actually plan ahead of time what you're doing!), I always start in tactic mode, blunder about for a bit (often letting tidy do some of the work), then end up with a successful tactic script. Now you're only half done, and you convert all the parts of the proof that are more succinct in term mode back into term mode.

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:45):

What is tidy?

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:46):

I found it

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:51):

Is there a preference for more specificity in the proofs? Eg why not leave tidy in the proof

view this post on Zulip Scott Viteri (Jun 27 2019 at 04:56):

Is there a Lean analog of crush?

view this post on Zulip Mario Carneiro (Jun 27 2019 at 04:56):

that's tidy

view this post on Zulip Mario Carneiro (Jun 27 2019 at 04:57):

You don't want to leave tidy in the proof because it's slow. It's basically a meta-tactic that finds a tactic script that you should use in place of tidy

view this post on Zulip Scott Viteri (Jun 27 2019 at 05:06):

makes sense

view this post on Zulip Scott Viteri (Jun 27 2019 at 05:08):

It seems that in order to find tidy in emacs definition search I must first import it

view this post on Zulip Scott Viteri (Jun 27 2019 at 05:10):

which I guess is fine, I could just grep through my mathlib directory if I'm looking for something

view this post on Zulip Scott Viteri (Jun 27 2019 at 05:11):

but is this expected behavior

view this post on Zulip Mario Carneiro (Jun 27 2019 at 05:17):

yes, this is unfortunate but unavoidable

view this post on Zulip Mario Carneiro (Jun 27 2019 at 05:17):

You can try importing everything if you want the searches to have good results, but that can take a lot of memory

view this post on Zulip Scott Viteri (Jun 27 2019 at 05:24):

ok

view this post on Zulip Scott Viteri (Jun 27 2019 at 05:33):

Thanks for the help!

view this post on Zulip Scott Viteri (Jun 27 2019 at 06:47):

Where can I find documentation for a tactic such as apply_assumption?

view this post on Zulip Kevin Buzzard (Jun 27 2019 at 06:49):

Not at a computer right now but there's a big file in docs in mathlib which contains information about most tactics. Is it docs/tactics.md or something?

view this post on Zulip Scott Viteri (Jun 27 2019 at 06:51):

This is useful for mathlib, thanks

view this post on Zulip Scott Viteri (Jun 27 2019 at 06:52):

but apply_assumption is in core.lean

view this post on Zulip Scott Morrison (Jun 27 2019 at 06:52):

You can also just type apply_assumption inside a begin ... end block, and hover the mouse over it. The tooltip that pops up should contain the doc-comment, which is usually just a slightly abbreviated version of the documentation in docs/tactics.md.

view this post on Zulip Scott Morrison (Jun 27 2019 at 06:52):

Read the definition, then. :-)

view this post on Zulip Scott Morrison (Jun 27 2019 at 06:52):

Put your cursor in apply_assumption, and hit F12 to jump to the definition.

view this post on Zulip Scott Morrison (Jun 27 2019 at 06:53):

The community branch of Lean would probably accept PRs adding doc comments to any/all of these core tactics! :-)

view this post on Zulip Scott Morrison (Jun 27 2019 at 06:53):

(Remember here that core Lean is frozen while development of Lean 4 takes place, so the community branch, which is only just getting off the ground now, is the only place we can improve the documentation of core stuff.)

view this post on Zulip Scott Viteri (Jun 27 2019 at 06:54):

I take back what I said -- apply assumption is in mathlib/src/tactic/core.lean

view this post on Zulip Scott Viteri (Jun 27 2019 at 06:55):

so why doesn't docs/tactics.md mention it?

view this post on Zulip Scott Morrison (Jun 27 2019 at 06:56):

Sorry about the confusing naming. src/tactic/core.lean is really basic tooling stuff (mostly not used interactively). src/tactic/basic.lean is all the most common interactive tactics, and src/tactic/default.lean is the kitchen sink, importing nearly all the mathlib defined tactics.

view this post on Zulip Scott Morrison (Jun 27 2019 at 06:57):

Probably because apply_assumption has been around a long time, perhaps predating docs/tactics.md? I'm not sure. Comment PR definitely accepted. :-)

view this post on Zulip Scott Viteri (Jun 27 2019 at 06:59):

Where does the tooltip come from?

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:00):

Because I do get a short description this way

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:00):

The doc-comment.

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:00):

When you make a definition, you can put a comment before it

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:00):

using the /-- ... -/ syntax (note the double hyphen at the open comment)

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:00):

But the definition of apply_assumption has no such comment above it

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:00):

Hmm.

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:01):

Mine does?

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:01):

There are two apply_assumption s

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:01):

The one in solve_by_elim.lean has the comment

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:01):

When I hit F12 on apply_assumption, I was taken to the one in solve_by_elim.lean.

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:02):

Ah!

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:02):

There are very often two versions of a given tactic.

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:02):

One in the tactic.interactive namespace, and one in the tactic namespace.

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:02):

Do you often have to be careful which version of a tactic you are importing?

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:02):

The interactive one is accessible in begin ... end blocks, and very often does some parsing tricks so you can conveniently control it

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:03):

and non-interactive one is usually not intended for use in begin ... end blocks, but instead by other people writing tactics.

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:03):

ok

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:03):

Unless you know what you're doing, typically always use the interactive version.

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:07):

This did solve my original question though -- the documentation is (besides the tactics.md) in the comment above the definition. I just didn't see this because I was looking at the wrong version of the definition

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:13):

is leanprover-community/lean much different from the original?

view this post on Zulip Scott Morrison (Jun 27 2019 at 07:18):

I don't think so. Simon Hudon is the one to ask.

view this post on Zulip Scott Viteri (Jun 27 2019 at 07:20):

ok

view this post on Zulip Kevin Buzzard (Jun 27 2019 at 07:21):

It's not different enough from the original Lean to have ever made me contemplate switching.

view this post on Zulip Mario Carneiro (Jun 27 2019 at 07:37):

right now it's just accumulating bugfixes and little things

view this post on Zulip Mario Carneiro (Jun 27 2019 at 07:37):

we'll let you know when it's ready for prime time

view this post on Zulip Jesse Michael Han (Jun 27 2019 at 08:54):

helm often gives me the same error. i find it usually works again after C-c C-r

view this post on Zulip Kevin Kappelmann (Jun 28 2019 at 12:45):

What's the recommended way to use zeta-reduction at a hypothesis? E.g. going from hyp : let n : ℕ := 2 in 1 + 1 = n to hyp : 1 + 1 = 2? I know that delta at hyp works, but isn't this strictly speaking a zeta-reduction I am performing?
edit: fix typo

view this post on Zulip Kevin Buzzard (Jun 28 2019 at 12:46):

These are definitionally equal I guess, so you can just use change.

view this post on Zulip Kevin Kappelmann (Jun 28 2019 at 12:48):

yep, sorry for the typo. I do not want to re-state the unfolded hypothesis though.

view this post on Zulip Wojciech Nawrocki (Jun 28 2019 at 14:11):

Why do additive monoids have scalar multiplication defined in terms of exponentiation? I found this really surprising:

def add_monoid.smul [add_monoid α] (n : ) (a : α) : α :=
@monoid.pow (multiplicative α) _ a n

view this post on Zulip Kevin Buzzard (Jun 28 2019 at 14:17):

multiplicative alpha means "I know it's addition, but pretend it's multiplication". It's some sort of attempt to not duplicate effort.

view this post on Zulip Kevin Buzzard (Jun 28 2019 at 14:18):

a monoid and an additive monoid are the same, but Lean is less good than mathematicans at dealing with things like this. At least in this situation we have some automation to use.

view this post on Zulip Wojciech Nawrocki (Jun 28 2019 at 14:20):

That makes sense, but even when the monoid operation is interpreted as multiplication, is it conventional to call pow scalar multiplication? To me, smul seems to only make sense with vector spaces/modules.

view this post on Zulip Wojciech Nawrocki (Jul 10 2019 at 10:33):

Does anyone know why the strictness of when names are resolved is kind of flipped between quoted names and expressions (assuming I understand it correctly)? By this I mean that using `my.name the name is not resolved when parsing the tactic, while with ``my.name it is, so more backticks => resolve sooner. But with expressions, it's the opposite - with `(expr), symbols are resolved at parse time, with ``(expr) partially so, and with ```(expr) resolving symbols is deferred to tactic runtime. EDIT: fixed backticks, thanks Johan!

view this post on Zulip Johan Commelin (Jul 10 2019 at 10:39):

On Zulip formatting: Use more ```backticks ``to `surround ```the code then the number of `adjacent backticks in the code.

view this post on Zulip Kevin Buzzard (Jul 10 2019 at 12:30):

And use the "quote and reply" option to see exactly what Johan did :-)

view this post on Zulip Scott Viteri (Jul 10 2019 at 16:21):

Does the syntax

theorem perm_sort : forall l, sort l ~ l
| [] := refl
| (a::l) := ...

not give inductive hypotheses?

view this post on Zulip Scott Viteri (Jul 10 2019 at 16:22):

Right now in the second block I have proven
sort l ~ l, and could really use a forall

view this post on Zulip Mario Carneiro (Jul 10 2019 at 16:26):

use perm_sort l in the second block to access the IH

view this post on Zulip Scott Viteri (Jul 10 2019 at 16:27):

oh ok

view this post on Zulip Scott Viteri (Jul 10 2019 at 16:28):

Thanks

view this post on Zulip Scott Viteri (Jul 10 2019 at 17:00):

How do I specify which instance of a definition rw unfolds?

view this post on Zulip Scott Viteri (Jul 10 2019 at 17:01):

suppose I have the goal rev (rev (h :: t)) = h :: t

view this post on Zulip Scott Viteri (Jul 10 2019 at 17:02):

rw rev results in rev_aux (rev (h :: t)) nil = h :: t

view this post on Zulip Scott Viteri (Jul 10 2019 at 17:02):

But I want rw to act on the inner instance of rev

view this post on Zulip Scott Viteri (Jul 10 2019 at 17:06):

I just found change, which seems to do the trick

view this post on Zulip Jesse Michael Han (Jul 10 2019 at 17:25):

change will work if the rewrite is definitional, otherwise you can try convert_to which will let you supply the equality proof obligation after

conv {} will let you navigate inside an expression and surgically rewrite

view this post on Zulip Marc Huisinga (Jul 10 2019 at 23:16):

is there a neat way to only generalize a specific variable?

view this post on Zulip Yury G. Kudryashov (Jul 10 2019 at 23:22):

Hi, what is the meaning of @@?

view this post on Zulip Kevin Buzzard (Jul 10 2019 at 23:39):

is there a neat way to only generalize a specific variable?

Does the dosctring for generalize answer your question?

view this post on Zulip Kevin Buzzard (Jul 10 2019 at 23:42):

Hi, what is the meaning of @@?

It's explained just above here in TPIL. Searching for @@ didn't work for me but I knew it was in there.

view this post on Zulip Marc Huisinga (Jul 10 2019 at 23:43):

i don't think so - i should have been more clear, sorry! i'm looking for a neat way to generalize a specific occurence of a variable, not all of them

view this post on Zulip Marc Huisinga (Jul 11 2019 at 00:17):

oh, i guess something along the lines of

lemma foo {α : Type*} (P : α → α → Prop) (a : α) : P a a :=
begin
  have h : ∀ b : α, P b a, sorry,
  exact h a
end

will do

view this post on Zulip Yury G. Kudryashov (Jul 11 2019 at 00:20):

Is it possible to redefine the "default constructor"? I mean, the one used by ⟨⟩ notation.

view this post on Zulip Marc Huisinga (Jul 11 2019 at 00:25):

afaik you can only use that notation if there is only one constructor

view this post on Zulip Kevin Buzzard (Jul 11 2019 at 01:18):

You can make a second structure with the constructor you like and then define a map to the first structure. If they were classes you could do this with type class inference I guess (on a good day with a following wind)

view this post on Zulip Kevin Buzzard (Jul 11 2019 at 01:20):

You want more than

lemma foo {α : Type*} (P : α  α  Prop) (a : α) : P a a :=
begin
  suffices h :  b : α, P b a,
    exact h a,
  sorry
end

?

view this post on Zulip Kevin Buzzard (Jul 11 2019 at 01:21):

I am struggling a bit to imagine the syntax of what some super-precise generalize tactic would look like but I understand your question now (and don't know the answer)

view this post on Zulip Marc Huisinga (Jul 11 2019 at 08:36):

ah, suffices is a neat syntax, i forgot about that one.
it turns out that for my specific use case, simply a precise generalize wouldn't do. i also needed additional assumptions about b (in my use-case, α was list foo and i additionally needed b ⊆ a to prove my lemma).
it probably isn't a good idea to have tactics for use cases this concrete, and "suffices" is certainly readable enough.

view this post on Zulip Wojciech Nawrocki (Jul 11 2019 at 13:17):

What's the convention for defining stuff on structures that can be both mul-based and add-based, e.g. semigroup/add_semigroup? Should I define it on semigroup and then somehow transport to add_semigroup using additive, the other way around, or something else?

view this post on Zulip Chris Hughes (Jul 11 2019 at 13:22):

Define it on semigroup and transfer with to_additive.

view this post on Zulip Wojciech Nawrocki (Jul 11 2019 at 13:25):

Thanks Chris!

view this post on Zulip Kevin Buzzard (Jul 11 2019 at 14:15):

See group_theory/quotient_group.lean for an example of how this looks.

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 14:29):

Can the equational lemmas for a function do something more than definitional/beta-reduction? I have a goal of the form (simplified) fn1 (fn2 some_expr) = fn1 (fn2 other_expr), s.t. fn1 \comp fn2 takes both exprs to the same value (and the exprs contain some more calls to fn1/2). So, this should follow from refl, but it doesn't. If however I do repeat { rw [fn1] }, repeat { rw [fn2] } first, refl works.

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 15:26):

A related question - is there a tactic equivalent of #reduce?

view this post on Zulip Kevin Buzzard (Jul 13 2019 at 16:23):

The equation lemmas for a function are not always definitionally true

view this post on Zulip Kevin Buzzard (Jul 13 2019 at 16:24):

They're simp lemmas though so simp might work

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 17:23):

Huh okay, that is kind of surprising - I thought they were all refl. Thanks!

view this post on Zulip Mario Carneiro (Jul 13 2019 at 19:06):

The main time when they are not rfl is when well founded recursion is used. This has to do with why definitional equality is undecidable and lean's defeq is an underapproximation of the real thing

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 19:23):

Oooh yeah it is recursive - it's transitivity that's missing, right? It seemed to me like it should still reduce but is what you're saying that the has_well_foundeds prevent it from reducing?

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 19:26):

I came across this while trying to write some reflection tactics a la ring2, where in correctness you have (H : horner_expr.of_csexpr r₁ = horner_expr.of_csexpr r₂) by rfl. of_csexpr is defined recursively but it seems to reduce just fine, however I have something more like (of_csexpr r1).eval = (of_csexpr r2).eval, where eval is also recursive and this breaks (needs simp; refl).

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 19:26):

I can get rid of the evals so this isn't really a problem, just confusing.

view this post on Zulip Mario Carneiro (Jul 13 2019 at 19:30):

Structural recursion is fine, it's just when you use well founded recursion, i.e. recursion on acc that it gets flaky

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 19:37):

I see, I'm doing some reassociation which I think has to rely on sizeof:

def reassoc: Expr -> Expr
| (Mul (Mul a b) c) := Mul (reassoc a) $ reassoc (Mul b c)
| e := e

view this post on Zulip Mario Carneiro (Jul 13 2019 at 19:49):

Right, that's not a structural recursion, but you can rewrite it to be one

view this post on Zulip Wojciech Nawrocki (Jul 13 2019 at 20:00):

Yup, refls now, thanks!

view this post on Zulip Wojciech Nawrocki (Jul 19 2019 at 23:32):

Is this assumption correct: "after compiling somefile.lean with lean --make, forall theorems in somefile, the resulting somefile.olean contains the theorems' names and types, but because they are in Prop and have already been typechecked, the proof terms are discarded and Lean trusts previously built modules to have correctly-typechecked definitions"?

view this post on Zulip Wojciech Nawrocki (Jul 19 2019 at 23:54):

Okay, it's partly correct and partly not. Lean keeps the proof terms (i.e. the "values" of theorem definitions) in .olean files, but they're stored with a high "trust level" value, and I think that when a such a high-trust definition is imported, its value is not typechecked again and the type is trusted.

view this post on Zulip Yury G. Kudryashov (Jul 21 2019 at 04:08):

From lean --help:

  --trust=num -t     trust level (default: max) 0 means do not trust any macro,
                     and type check all imported modules

view this post on Zulip Yury G. Kudryashov (Jul 21 2019 at 04:09):

I think, by default Lean trusts that all imported .olean files are correct but you can tell it to double-check them.

view this post on Zulip Lennard Henze (Jul 22 2019 at 16:32):

Trying one of the excercises I am stuck with deriving A \or \not A:

example : ¬ (A  ¬ A) :=
have h₂ : A  ¬ A, from sorry,
assume h₁ : (A  ¬ A),
show false, from or.elim h₂
        (assume : A,
           have h₃ : ¬A, from iff.mp h₁ this,
            show false, from h₃ this)
        (assume : ¬ A,
            have h₃ : A, from iff.mpr h₁ this,
            show false, from this h₃)

Can someone point me in the right direction?

view this post on Zulip Kevin Buzzard (Jul 22 2019 at 16:38):

This is just the law of the excluded middle, which is not true in constructive logic

view this post on Zulip Kevin Buzzard (Jul 22 2019 at 16:38):

Are you allowed to use classical logic?

view this post on Zulip Wojciech Nawrocki (Jul 22 2019 at 16:38):

(See also TPIL 11.6)

view this post on Zulip Kevin Buzzard (Jul 22 2019 at 16:39):

It can be done constructively I believe (but don't trust me, I am a classical guy)

view this post on Zulip Kevin Buzzard (Jul 22 2019 at 16:40):

It's something like classical.em, what you want

view this post on Zulip Lennard Henze (Jul 22 2019 at 16:41):

its just a task from https://leanprover.github.io/logic_and_proof/propositional_logic_in_lean.html, i have not read anything about classical logic being forbidden

view this post on Zulip Kenny Lau (Jul 22 2019 at 16:42):

lol

view this post on Zulip Lennard Henze (Jul 22 2019 at 16:43):

i think it is meant to be done without imports

view this post on Zulip Wojciech Nawrocki (Jul 22 2019 at 16:49):

Here is a constructive proof, adapted from iff_not_self:

example : ¬ (A  ¬ A) :=
assume h: A  ¬ A,
have hna: ¬A, from (
  assume ha: A,
  show false, from (h.mp ha) ha),
show false, from hna (h.mpr hna)

view this post on Zulip Lennard Henze (Jul 22 2019 at 16:53):

nice thanks!!

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 16:19):

Is there an escape sequence for producing french quotes in the web editor / VS Code? More generally, is there a comprehensive list of escape sequences? Ta.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:19):

Hey Gihan!

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:19):

It's in some translations.json file somewhere, hang on...

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:20):

https://github.com/leanprover/vscode-lean/blob/master/translations.json

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 16:21):

Thanks very much Kevin!

I see you're teaching M1F to a virtual tutee. Have you had success teaching Lean to corporeal M1F students?

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:22):

@Kenny Lau and @Chris Hughes are both Imperial undergraduates who have contributed far more than me to Lean's maths library.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:23):

\f< and \f> apparently

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:23):

I don't usually use them

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 16:24):

Amazing! I'm tempted to try this at Exeter, but I'm worried that formal proof may put off the bulk of students.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:25):

I have a lot of tips. If you do it naively then definitely you can put a lot of people off. One initial tip is not to teach people new maths and Lean at the same time.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:25):

by "people" I mean "UG mathematicians"

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:26):

so if it's your job to teach them new maths then it can get quite tricky finding the balance.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:27):

I'm speaking in Exeter at the end of Nov, we can maybe talk then. Unfortunately I'm giving the number theory seminar rather than a general colloquium.

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 16:32):

OK, that would be great. I look forward to it.

My main issue really is how to teach proof tout court. Most written arguments I see from new students are full of non sequiturs. I thought Lean might be a way for students to determine whether their arguments were valid.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:32):

This was one of the reasons I got interested in Lean too.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:33):

I'm sure this sort of software has got a lot of potential to change the way undergraduate mathematics is taught.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:33):

But I'm still very much experimenting with how to do it. Patrick Massot also tried

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:34):

using Lean with a bunch of UGs at Orsay in their introduction to proof course

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 16:36):

Thanks. I've also seen Jeremy Avigad's 'Logic and Proof' notes.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:37):

Yeah, we're all trying to change the world.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:37):

An education specialist is writing a paper about my intervention, should be ready next month apparently.

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:38):

She interviewed lots of M1F students

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 16:40):

I'd be interested in reading the article. Where will it be published?

view this post on Zulip Kevin Buzzard (Aug 05 2019 at 16:40):

Don't know, I guess they will have some education journal ecosystem but I don't know anything about it.

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 16:43):

Well, maybe I'll find out in November. See you then and thanks for the information.

view this post on Zulip Floris van Doorn (Aug 05 2019 at 19:44):

@Gihan Marasingha: If you see a character in VSCode, and you are wondering how to input it, you can also hover your mouse over the character, and in a pop-up it will tell you how to type it.

view this post on Zulip Gihan Marasingha (Aug 05 2019 at 21:56):

Thanks!

view this post on Zulip Kevin Kappelmann (Aug 14 2019 at 21:02):

Question related to proof irrelevance: I was wondering what Lean is doing in this example:

structure test := (n : ) (pos: 0 < n)

example {t1 t2 : test} (h : t1.n = t2.n) : t1 = t2  :=
begin
  cases t1 with n1 pos1,
  cases t2 with n2 pos2, -- current goal : {n := n1, pos := pos1} = {n := n2, pos := pos2}
  suffices : n1 = n2, by simpa only [], -- current goal : n1 = n2, but why?
  exact h
end

Is simp matching the parts of the structure that live in Prop and decides that we need n1 = n2? How is it deciding that? Just by unification? (PS. I know that Lean auto-generates test.mk.inj_eq)

view this post on Zulip Floris van Doorn (Aug 14 2019 at 21:37):

Yeah, probably these mk.inj_eq lemmas are hard-coded to be simp lemmas, even when doing simp only.

view this post on Zulip Rob Lewis (Aug 14 2019 at 21:53):

The simp option constructor_eq := ff disables this behavior.

view this post on Zulip Kevin Kappelmann (Sep 03 2019 at 14:32):

Given a function f taking arguments from a set S : set ℕ, a number n : ℕ, and the knowledge that n ∈ S, how can I apply f on n, that is, how do I make this work:

import data.set.basic

example {S : set } {n : } (f : S  ) (hyp : n  S) :  := f n -- type mismatch

view this post on Zulip Chris Hughes (Sep 03 2019 at 14:36):

f ⟨n, hyp⟩

view this post on Zulip Kevin Kappelmann (Sep 03 2019 at 14:37):

Ahh, right! Thanks - you're the best!

view this post on Zulip Patrick Massot (Sep 03 2019 at 14:42):

Maybe the piece you missed is that Lean can make sense of (f : S → ℕ) only because it inserts a coercion of S to the subtype {n : ℕ // n ∈ S}

view this post on Zulip Kevin Kappelmann (Sep 03 2019 at 14:53):

Maybe the piece you missed is that Lean can make sense of (f : S → ℕ) only because it inserts a coercion of S to the subtype {n : ℕ // n ∈ S}

That was indeed the case :)

view this post on Zulip Gihan Marasingha (Sep 08 2019 at 09:17):

I tried proving a very simple result, the formula 6i=0ni2=n(n+1)(2n+1)6\sum_{i=0}^n i^2 = n(n+1)(2n+1). My Lean proof, using equational reasoning, is much longer than I anticipated (30 lines). Could someone suggest a way to shorten the proof?

theorem ssquares_formula (n : ) : 6*(ssquares n) = n*(n+1)*(2*n+1) :=
nat.rec_on n
rfl -- trivial base case
(
assume k,
assume h :  6*(ssquares k) = k*(k+1)*(2*k+1),
show 6*(ssquares (k+1)) = (k+1)*((k+1)+1)*(2*(k+1)+1), from
calc
6*(ssquares (k+1)) = 6*((k+1)*(k+1) + (ssquares k)) : rfl
    ... = 6*((k+1)*(k+1)) + k*(k+1)*(2*k+1) : by rw [left_distrib, h]
    ... = 6*(k+1)*(k+1) + k*(k+1)*(2*k+1) : by rw mul_assoc
    ... = (k+1)*6*(k+1) + k*(k+1)*(2*k+1) : by rw mul_comm 6 (k+1)
    ... = (k+1)*6*(k+1) + (k+1)*k*(2*k+1) : by rw mul_comm k (k+1)
    ... = (k+1)*(6*(k+1)) + (k+1)*(k*(2*k+1)) : by rw [mul_assoc, mul_assoc]
    ... = (k+1)*(6*(k+1)+(k*(2*k+1))) : by rw left_distrib
    ... = (k+1)*(6*k+6+(k*(2*k+1))) : by rw [left_distrib 6 k 1, mul_one]
    ... = (k+1)*(6*k+6+(k*(2*k)+k)) : by rw [left_distrib k (2*k) 1, mul_one]
    ... = (k+1)*((3+3)*k+6+(k*(2*k)+k)) : rfl
    ... = (k+1)*(3*k+3*k+6+(k*(2*k)+k)) : by rw right_distrib 3 3 k
    ... = (k+1)*(3*k+3*k+(6+k*(2*k))+k) : by rw [add_assoc,add_assoc]
    ... = (k+1)*(3*k+3*k+(k*(2*k)+6)+k) : by rw add_comm 6 (k*(2*k))
    ... = (k+1)*(3*k+(3*k+k*(2*k))+6+k) : by rw [add_assoc,add_assoc]
    ... = (k+1)*(3*k+(k*(2*k)+3*k)+6+k) : by rw add_comm (3*k) (k*(2*k))
    ... = (k+1)*((3*k+k*(2*k))+3*k+6+k) : by rw [add_assoc,add_assoc]
    ... = (k+1)*((k*(2*k)+3*k)+3*k+6+k) : by rw add_comm (3*k) (k*(2*k))
    ... = (k+1)*(k*(2*k)+3*k+3*k+(6+k)) : by rw add_assoc
    ... = (k+1)*(k*(2*k)+3*k+3*k+(k+6)) : by rw add_comm 6 k
    ... = (k+1)*(k*(2*k)+3*k+(3*k+k)+6) : by rw [add_assoc,add_assoc]
    ... = (k+1)*(k*(2*k)+3*k+(3*k+k*1)+6) : by rw mul_one
    ... = (k+1)*(k*(2*k)+3*k+(3*k+1*k)+6) : by rw mul_comm k 1
    ... = (k+1)*(k*(2*k)+3*k+((3+1)*k)+6) : by rw right_distrib 3 1 k
    ... = (k+1)*(k*(2*k)+3*k+((2*2)*k)+6) : rfl
    ... = (k+1)*(k*(2*k)+3*k+(2*(2*k))+6) : by rw mul_assoc 2 2 k
    ... = (k+1)*(k*(2*k)+3*k+(2*(2*k)+2*3)) : rfl
    ... = (k+1)*(k*(2*k)+k*3+(2*(2*k)+2*3))  : by rw mul_comm 3 k
    ... = (k+1)*(k*(2*k)+k*3+2*((2*k)+3)) : by rw left_distrib 2 (2*k) 3
    ... = (k+1)*(k*(2*k+3)+2*(2*k+3)) : by rw left_distrib k (2*k) 3
    ... = (k+1)*((k+2)*(2*k+3)) : by rw right_distrib k 2 (2*k+3)
    ... = (k+1)*((k+2)*(2*k+2*1+1)) : rfl
    ... = (k+1)*((k+2)*(2*(k+1)+1)) : by rw left_distrib
    ... = (k+1)*(k+2)*(2*(k+1)+1) : by rw mul_assoc
    ... = (k+1)*((k+1)+1)*(2*(k+1)+1) : rfl
)

view this post on Zulip Keeley Hoek (Sep 08 2019 at 09:20):

What is your definition of ssquares?

view this post on Zulip Gihan Marasingha (Sep 08 2019 at 09:21):

def ssquares :   
| 0     := 0
| (n+1) := (n+1)*(n+1) + (ssquares n)

view this post on Zulip Keeley Hoek (Sep 08 2019 at 09:23):

Let me introduce you to the ring tactic of mathlib:

import tactic

def ssquares :   
| 0     := 0
| (n+1) := (n+1)*(n+1) + (ssquares n)

theorem ssquares_formula (n : ) : 6*(ssquares n) = n*(n+1)*(2*n+1) :=
nat.rec_on n
rfl -- trivial base case
$
assume k,
assume h :  6*(ssquares k) = k*(k+1)*(2*k+1),
show 6*(ssquares (k+1)) = (k+1)*((k+1)+1)*(2*(k+1)+1), from
calc
6*(ssquares (k+1)) = 6*((k+1)*(k+1) + (ssquares k)) : rfl
    ... = 6*((k+1)*(k+1)) + k*(k+1)*(2*k+1) : by rw [left_distrib, h]
    ... = (k+1)*((k+1)+1)*(2*(k+1)+1) : by ring

view this post on Zulip Keeley Hoek (Sep 08 2019 at 09:24):

But really, mathlib has machinery for doing finite sums already, without starting from the beginning e.g. with your definition of ssquares. A place to start to look is in data.finset, for finset.sum.

view this post on Zulip Gihan Marasingha (Sep 08 2019 at 09:25):

@Keeley Hoek thanks so much.

view this post on Zulip Keeley Hoek (Sep 08 2019 at 09:34):

@Gihan Marasingha , here is also a way it could be done in tactic mode

import tactic

def ssquares :   
| 0     := 0
| (n + 1) := (ssquares n) + (n + 1) * (n + 1)

theorem ssquares_formula (n : ) : 6 * (ssquares n) = n * (n + 1) * (2 * n + 1) :=
begin
  induction n with k h,
  { refl },
  { dsimp [ssquares],
    rw [left_distrib, h],
    rw (show nat.succ k = k + 1, from rfl), -- It is sad that this line is needed
    ring, }
end

view this post on Zulip Keeley Hoek (Sep 08 2019 at 09:34):

@Mario Carneiro, why is the commented line needed there? Is this a bug?

view this post on Zulip Mario Carneiro (Sep 08 2019 at 09:37):

Ring doesn't know about succ

view this post on Zulip Keeley Hoek (Sep 08 2019 at 09:37):

How do we make it

view this post on Zulip Mario Carneiro (Sep 08 2019 at 09:37):

I guess it is one more case in the recursion

view this post on Zulip Keeley Hoek (Sep 08 2019 at 09:39):

Is there any appetite for some tactic-ish thing normalize which does all these common rewrites? Kevin could make his induction' just (essentially) induction >> normalize

view this post on Zulip Mario Carneiro (Sep 08 2019 at 09:45):

I think the normalization is domain specific

view this post on Zulip Gihan Marasingha (Sep 09 2019 at 19:19):

Lean works fine on my Windows machine, but I have a couple of issues on the Mac.

My main problems is that VS Code doesn't seem to access the added dependencies.

From the Mac command line, If I move into the directory of the Lean project I've already created on Windows (and synced via OneDrive) to which I have already added mathlib as a dependency, I can execute .lean files perfectly, but I get import resolution errors when attempting the same through VS Code.

For example, if the file tsum.lean has the contents

import algebra.big_operators

open finset

def tsum (n : ) :  :=
    sum (range (n+1)) (λ i, i)

#eval tsum 10

then executing, at the terminal, lean tsum.lean produces the expected output 55.

But VS Code presents me with the error messages:

file 'algebra/big_operators' not found in the LEAN_PATH

invalid import: algebra.big_operators
could not resolve import: algebra.big_operators

view this post on Zulip Bryan Gin-ge Chen (Sep 09 2019 at 19:45):

Did you open the Lean package directory in VS Code or just the file tsum.lean? The vscode-lean extension won't work properly unless you do the former.

view this post on Zulip Gihan Marasingha (Sep 09 2019 at 20:22):

Thanks so much @Bryan Gin-ge Chen ! It wasn't a Mac problem after all. Just me not understanding how to use VS Code.

view this post on Zulip Bryan Gin-ge Chen (Sep 09 2019 at 20:23):

We could probably have the extension pop up a warning if it can't find a leanpkg.toml file.

view this post on Zulip Kevin Buzzard (Sep 09 2019 at 21:19):

@Gihan Marasingha very early on in my Lean career I wrote a blog post about proving mathematical stuff by induction: https://xenaproject.wordpress.com/2018/03/30/proofs-by-induction/ . The first response in the comments is by a 1st year undergraduate giving lots of examples of how one can do various things in Lean, maybe it's helpful for you? He includes a link to his code.

view this post on Zulip Sayantan Majumdar (Sep 19 2019 at 22:32):

is there something wrong in the documentation in "prepositions and proof" in the "3.6 Examples of Prepositional Validities" when they write
p \and false \iff false

view this post on Zulip Kevin Buzzard (Sep 19 2019 at 22:35):

...that example : ¬(p ↔ ¬p) := sorry can be done constructively? That's what people usually ask about this section ;-) Yes, it can be done constructively.

view this post on Zulip Sayantan Majumdar (Sep 19 2019 at 22:36):

no is there something wrong with p \and false \iff false

view this post on Zulip Kevin Buzzard (Sep 19 2019 at 22:36):

I think that one is OK.

view this post on Zulip Sayantan Majumdar (Sep 19 2019 at 22:38):

how does false implies p is false?

view this post on Zulip Kevin Buzzard (Sep 19 2019 at 22:38):

false implies anything ;-)

view this post on Zulip Kevin Buzzard (Sep 19 2019 at 22:38):

example (p : Prop) : p  false  false :=
begin
  split,
  { intro h,
    cases h,
    assumption,
  },
  {
    intro h,
    cases h,
  }
end

view this post on Zulip Kevin Buzzard (Sep 19 2019 at 22:38):

false is an inductive type with no constructors, so the induction principle for false, namely false.elim is just false -> X for any X.

view this post on Zulip Kevin Buzzard (Sep 19 2019 at 22:39):

It might be easier to think of things in terms of classical logic. Then P is either true or false, and in either case we see both sides are false.

view this post on Zulip Kevin Buzzard (Sep 19 2019 at 22:40):

example (p : Prop) : p  false  false := and.right, false.elim

view this post on Zulip Sayantan Majumdar (Sep 19 2019 at 22:44):

thanks

view this post on Zulip Yufan Lou (Oct 02 2019 at 01:35):

How do I fix this?

import data.nat.modeq
import tactic.library_search

example (a b : ) : a^2  b^2 [MOD 2]  a  b [MOD 2] :=
begin
  assume hyp,
  have : 2  b^2 - a^2, from nat.modeq.dvd_of_modeq hyp,
end
7:29 error:
invalid type ascription, term has type
  ↑2 ∣ ↑(b ^ 2) - ↑(a ^ 2)
but is expected to have type
  2 ∣ b ^ 2 - a ^ 2
state:
2 goals
a b : ℕ,
hyp : a ^ 2 ≡ b ^ 2 [MOD 2]
⊢ 2 ∣ b ^ 2 - a ^ 2

a b : ℕ,
hyp : a ^ 2 ≡ b ^ 2 [MOD 2],
this : 2 ∣ b ^ 2 - a ^ 2
⊢ a ≡ b [MOD 2]

view this post on Zulip Floris van Doorn (Oct 02 2019 at 02:01):

Your have : 2 ∣ b^2 - a^2 statement is probably not what you want here. The b^2 and a^2 are natural numbers, so - is subtraction between natural numbers. To make the output a natural number, so we define it as 0 when a^2 > b^2. This "truncated" subtraction is very often not what you want to use.

view this post on Zulip Floris van Doorn (Oct 02 2019 at 02:01):

So you want to give Lean a hint that you want to use integer subtraction:

import data.nat.modeq data.int.all

example (a b : ) : a^2  b^2 [MOD 2]  a  b [MOD 2] :=
begin
  assume hyp,
  have : 2  (b : )^2 - a^2, exact_mod_cast nat.modeq.dvd_of_modeq hyp,
  -- rw [nat.modeq.modeq_iff_dvd] at hyp, norm_cast at hyp,
end

view this post on Zulip Floris van Doorn (Oct 02 2019 at 02:02):

I added an import, so that Lean knows about exponentiation of integers. You can alternatively also rewrite with nat.modeq.modeq_iff_dvd (see commented out code)

view this post on Zulip Floris van Doorn (Oct 02 2019 at 02:03):

norm_cast and exact_mod_cast are useful tactics which will automatically deal with the cast from nat to int.

view this post on Zulip Floris van Doorn (Oct 02 2019 at 02:03):

See https://github.com/leanprover-community/mathlib/blob/master/docs/tactics.md#norm_cast

view this post on Zulip Kevin Buzzard (Oct 02 2019 at 06:30):

One very confusing point for beginners is that the natural number 2 and the integer 2 are not "equal" in Lean -- indeed it doesn't even make sense to ask that they are equal, because they don't have the same type. I would suggest that you work with integers all the way through rather than natural numbers, because what you want is true for integers. Of course then you have to change all the functions you use to the integer version :-/ Yes, this isn't like the way mathematicians treat it -- I know :-/

view this post on Zulip Yufan Lou (Oct 02 2019 at 22:44):

LOL I really overlooked that, thanks a lot

view this post on Zulip Yufan Lou (Oct 02 2019 at 22:47):

I guess it's just better to work under integer most of the time

view this post on Zulip Reid Barton (Oct 03 2019 at 02:14):

Clearly the natural numbers weren't meant to be formalized

view this post on Zulip Yufan Lou (Oct 03 2019 at 02:19):

example (a b : ) : a^2  b^2 [ZMOD 2]  a  b [ZMOD 2] :=
begin
  assume hyp,
  have : 2  b^2 - a^2, from int.modeq.modeq_iff_dvd.mp hyp,
  have : 2  (b - a) * (b + a), by library_search,
  library_search
end

back at it but this gives me fail, meanwhile I found this with library_search

example (a b : ) : a^2 - b^2 = (a + b) * (a - b) := sq_sub_sq a b

How do I apply it?

view this post on Zulip Yufan Lou (Oct 03 2019 at 02:29):

nvm I was dumb XD forgot to specify at with rw

view this post on Zulip Yufan Lou (Oct 03 2019 at 02:47):

ahhhh... now I have to apply the fundamental theorem of arithmetic but don't know how

view this post on Zulip Jesse Michael Han (Oct 03 2019 at 03:57):

you can do it by case exhaustion on a and b:

-- requires import data.zmod.basic
example (a b : ) : a^2  b^2 [ZMOD 2]  a  b [ZMOD 2] :=
begin
  assume hyp,
  cases int.mod_two_eq_zero_or_one a with H₁ H₁;
  cases int.mod_two_eq_zero_or_one b with H₂ H₂,
    { change _  0 [ZMOD 2] at H₁, change _  0 [ZMOD 2] at H₂,
      have := @zmod.eq_iff_modeq_int 2, simp at this,
      rw this at  H₁ H₂ hyp, cc },
    { change _  0 [ZMOD 2] at H₁, change _  1 [ZMOD 2] at H₂,
      have := @zmod.eq_iff_modeq_int 2, simp at this,
      rw this at  H₁ H₂ hyp,
      suffices : (0 : zmod 2) = (1 : zmod 2),
        by simp*,
      simp at H₁ H₂, simp[*, -hyp] at hyp, simpa using hyp },
    { change _  1 [ZMOD 2] at H₁, change _  0 [ZMOD 2] at H₂,
      have := @zmod.eq_iff_modeq_int 2, simp at this,
      rw this at  H₁ H₂ hyp,
      suffices : (1 : zmod 2) = (0 : zmod 2),
        by simp*,
      simp at H₁ H₂, simp[*, -hyp] at hyp, simpa using hyp },
    { change _  1 [ZMOD 2] at H₁, change _  1 [ZMOD 2] at H₂,
      have := @zmod.eq_iff_modeq_int 2, simp at this,
      rw this at  H₁ H₂ hyp, cc }
end

there's also fermat's little theorem for zmod, which might give a cleaner proof

view this post on Zulip Kenny Lau (Oct 03 2019 at 04:28):

import data.zmod.quadratic_reciprocity

theorem frob {p : } (hp : nat.prime p) {a : zmodp p hp} : a ^ p = a :=
decidable.by_cases
  (assume ha : a = 0, by rw [ha, zero_pow hp.pos])
  (assume ha : a  0, by conv_lhs { congr, skip, rw  nat.sub_add_cancel (show p  1, from le_of_lt hp.one_lt) };
    rw [pow_add, zmodp.fermat_little hp ha, pow_one, one_mul])

theorem frob' {p : } (hp : nat.prime p) {a : } : a ^ p  a [ZMOD p] :=
by rw [ zmodp.eq_iff_modeq_int hp, int.cast_pow, frob]

example (a b : ) (h : a^2  b^2 [ZMOD 2]) : a  b [ZMOD 2] :=
calc  a  a^2 [ZMOD 2] : (frob' nat.prime_two).symm
    ...  b^2 [ZMOD 2] : h
    ...  b [ZMOD 2] : frob' nat.prime_two

view this post on Zulip Yufan Lou (Oct 03 2019 at 08:30):

Thank you both! I am understanding the proofs by tracing them step by step. I see that the key is to understand zmod n itself as a number type and either turning the mod congruence in nat into equality in zmod n and prove it there, or turning equality in zmod n into mod congruence in nat and apply them here. Hmm... I have a vague intuition about this from my Haskell experience, but I need to think hard about how to explain this to my maths colleagues...

I still don't get many intricacies in there either, like why I need to show 0 = 1 and why -hyp is necessary in simp[*, -hyp]. conv_lhs has not yet been documented. The first two steps congr, skip seems very arbitrary. Although I understand the proofs now, I can hardly imagine writing them.

view this post on Zulip Chris B (Oct 18 2019 at 18:57):

Is there a nicer way of doing this?

lemma always_less :  (a : ), (if a < 5 then a else 2) < 6 :=
λ a, decidable.cases_on (nat.decidable_lt a 5)
  (λ hnc, dec_trivial)
  (λ hc, show a < 6, from lt.step hc)

view this post on Zulip Kenny Lau (Oct 18 2019 at 20:06):

import tactic.split_ifs tactic.omega

lemma always_less (a : ) : (if a < 5 then a else 2) < 6 :=
by split_ifs; omega

view this post on Zulip Chris B (Oct 18 2019 at 20:58):

Rad, thanks. I didn't know about split_ifs.

view this post on Zulip Kenny Lau (Oct 18 2019 at 21:00):

I'm Kenny, but you're welcome

view this post on Zulip Yury G. Kudryashov (Oct 19 2019 at 14:31):

How do I prove ∀ x : ℤ, 0 ≤ x → x ≤ 1 → x ∈ ({0, 1} : set ℤ)?

view this post on Zulip Yury G. Kudryashov (Oct 19 2019 at 14:36):

Do we have something like fintype {m : ℤ | a ≤ m /\ m < b}?

view this post on Zulip Kevin Buzzard (Oct 19 2019 at 15:42):

There was a thread about this only recently

view this post on Zulip Kevin Buzzard (Oct 19 2019 at 15:43):

I mean the fintype

view this post on Zulip Kevin Buzzard (Oct 19 2019 at 15:50):

import tactic.interactive

example :  x : , 0  x  x  1  x  ({0, 1} : set ) :=
begin
  intros x h0 h1,
  rw le_iff_lt_or_eq at h0,
  cases h0, swap,
    rw h0, right, left, refl,
  rw [int.lt_iff_add_one_le, zero_add, le_iff_lt_or_eq] at h0,
  cases h0,
    exfalso,
    rw lt_iff_not_ge at h0,
    apply h0,
    exact h1,
  left, exact h0.symm,
end

view this post on Zulip Kevin Buzzard (Oct 19 2019 at 15:52):

https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Some.20numerology That's more than you need for the fintype. As you can see, I partially PR'ed it (some nat lemmas) and then teaching started at my university and I never finished the job. Feel absolutely free to PR that stuff! I'm still snowed under until November.

view this post on Zulip Yury G. Kudryashov (Oct 19 2019 at 15:53):

Thank you for the link. I'll possibly PR it next week.

view this post on Zulip Patrick Massot (Oct 19 2019 at 21:00):

The correct thing to do is probably to resume work on https://github.com/leanprover-community/mathlib/tree/nat_cases

view this post on Zulip Chris B (Oct 20 2019 at 17:10):

If anyone has opinions about when to prefer a decidable prop over a boolean valued function as a predicate I'd like to read them if you get a moment. In a general context like lists, core doesn't seem to take a hard line stance either way IE list.filter and list.partition use decidable predicates whereas list.all and list.any use a boolean valued function. Mathlib often defines a function for both.

view this post on Zulip Andrew Ashworth (Oct 20 2019 at 17:39):

If you're going to still use Lean next year, I would use a bool-valued function

view this post on Zulip Andrew Ashworth (Oct 20 2019 at 17:40):

Lean 4's core library is moving towards explicit usage of boolean-valued predicates

view this post on Zulip Chris B (Oct 20 2019 at 18:37):

Thanks, that definitely simplifies things, bool it is then.

view this post on Zulip Yury G. Kudryashov (Oct 25 2019 at 13:19):

Hi, is it possible to express ∃ b > a, p b using < only? I understand that I can write ∃ b (H : a < b), p b but this is less readable.

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 13:21):

I think what you suggest (the less readable thing) is what we're supposed to be writing nowadays.

view this post on Zulip Seewoo Lee (Oct 25 2019 at 13:56):

Hi, here's a noob question: I'm trying to prove currying & uncurrying, i.e. (p -> q -> r) <-> ((p \and q) -> r). Here's my try:

theorem t3 : ((p ∧ q) → r) → (p → q → r) :=
    assume h₁ : (p ∧ q) → r,
    assume hp : p,
    assume hq : q,
    have h₂ : p ∧ q, from and.intro hp hq,
    h₁ h₂

theorem t4 : (p → q → r) → ((p ∧ q) → r) :=
    assume h₁ : p → q → r,
    assume h₂ : p ∧ q,
    have hp : p, from and.left h₂,
    have hq : q, from and.right h₂,
    have h₃ : q → r, from h₁ hp,
    have hr : r, from h₃ hq
    hr

t3 seems to have no problem, but t4 has. It gives an error like

function expected at
  h₃ hq
term has type
  r

and

unknown identifier 'hr'

but I can't find the reason. Any helps?

view this post on Zulip Seewoo Lee (Oct 25 2019 at 13:58):

I forgot one: I put variables p q r : Prop before t3 and t4, of course.

view this post on Zulip Kenny Lau (Oct 25 2019 at 13:59):

because you forgot a comma

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:00):

these proofs are so hard to debug because they're not in tactic mode :-/

view this post on Zulip Seewoo Lee (Oct 25 2019 at 14:00):

Oh you're right, thanks!

view this post on Zulip Seewoo Lee (Oct 25 2019 at 14:00):

Is there any efficient way to do these? I'm still not familiar with lean's grammar.

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:01):

"Don't forget the comma" occurs at least once in about the first six levels of http://wwwf.imperial.ac.uk/~buzzard/xena/natural_number_game/

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:01):

because extensive testing showed that it was by far the most common error which newcomers made.

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:01):

often in bold face

view this post on Zulip Kenny Lau (Oct 25 2019 at 14:02):

Is there any efficient way to do these? I'm still not familiar with lean's grammar.

variables p q r : Prop

theorem t3 : ((p  q)  r)  (p  q  r) :=
λ h₁ hp hq, h₁ hp, hq

theorem t4 : (p  q  r)  ((p  q)  r) :=
λ h₁ h₂, h₁ h₂.1 h₂.2

view this post on Zulip Seewoo Lee (Oct 25 2019 at 14:03):

@Kenny Lau This is much better, thanks!

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:04):

theorem t4 : (p  q  r)  ((p  q)  r) :=
begin
  intro h₁, -- I can see what is happening
  intro h₂, -- I can still see what is happening
  have hp : p, -- oh wow now I can see I have two goals
    exact and.left h₂, -- now back down to one
  have hq : q, -- this is so much better than what TPIL chapter 3 says
    exact and.right h₂, -- I wish I had read chapter 5 much earlier
  have h₃ : q  r, -- :D
    exact h₁ hp,
  have hr : r,
    exact h₃ hq,
  exact hr,
end

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:04):

Kenny's method is a pure term mode proof. To write these you need to know the trick with _

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:05):

This one was particularly easy, but in a longer one you can write something like

theorem t4 : (p  q  r)  ((p  q)  r) :=
λ h₁ h₂, h₁ _ _

and hover over the _s to see what needs to go there.

view this post on Zulip Kevin Buzzard (Oct 25 2019 at 14:06):

In tactic mode you can see everything at all times, so it's better for mathematician beginners. What Kenny is saying is perhaps more appealing for CS beginners, as long as you know the _ trick. You are just making the terms explicitly there.

view this post on Zulip Seewoo Lee (Oct 25 2019 at 14:09):

Yes I agree with you, and I just know what tactic mode is! Both seems great for me but tactic thing seems more intuitive.

view this post on Zulip Jason Gross (Oct 30 2019 at 04:08):

Question: does simp / rewrite work under binders?

view this post on Zulip Kevin Buzzard (Oct 30 2019 at 04:13):

not very well. Suggestions: (1) erw "extended rewrite" sometimes gets to places standard rw doesn't get to. (2) learn about conv mode: https://github.com/leanprover-community/mathlib/blob/master/docs/extras/conv.md

view this post on Zulip Johan Commelin (Oct 30 2019 at 05:27):

Actually simp usually does quite well, I think. But rw is really bad at this.

view this post on Zulip Jason Gross (Oct 30 2019 at 06:47):

Thanks

view this post on Zulip Jason Gross (Oct 30 2019 at 06:47):

Another question: Does pp.max_depth do anything? I have it set to 1000000000 and still see in my goal

view this post on Zulip Floris van Doorn (Oct 30 2019 at 13:14):

The _ in your goal is likely a proof. Use pp.proofs

view this post on Zulip Jason Gross (Oct 30 2019 at 19:31):

@Floris van Doorn It's not _, it's , and my term has ~no proofs. I see things like […, …, …, …, (… * 2 ^256, …), (and then more), I don't see how these could possibly be proofs

view this post on Zulip Chris Hughes (Oct 30 2019 at 19:41):

There's another pp option that does it. I don't remember what it's called.

view this post on Zulip Floris van Doorn (Oct 30 2019 at 19:41):

Oh, I have never encountered that. Does setting pp.max_steps help?

view this post on Zulip Jason Gross (Oct 30 2019 at 20:00):

That does seem to help, but not interactively. I get 11:1: excessive memory consumption detected at 'replace' (potential solution: increase memory consumption threshold) And it takes something like 15 GB on the command line. Here's an example:

@[simp]
def big :     
| v 0 := v
| v (nat.succ c) := big (v + v) c

set_option pp.max_depth 1000000000
set_option pp.max_steps 1000000000
example (v : ) : big v 20 = 0 :=
begin
  simp only [big]
end

view this post on Zulip Jason Gross (Oct 30 2019 at 20:36):

If I get kernel failed to type check declaration 'int.pow_of_nat' this is usually due to a buggy tactic or a bug in the builtin elaborator on a definition I'm giving by rfl, is that a bug in lean?

view this post on Zulip Scott Morrison (Oct 30 2019 at 20:42):

Probably not... :-) Can you minimise your example enough to post here?

view this post on Zulip Jason Gross (Oct 30 2019 at 20:58):

def int.pow_nat :     
| (int.of_nat b) e := int.of_nat (b ^ e)
| (int.neg_succ_of_nat b) 0 := 1
| (int.neg_succ_of_nat b) (k+1) := (int.neg_succ_of_nat b) * int.pow_nat (int.neg_succ_of_nat b) k

instance int_has_pow_nat : has_pow int nat := int.pow_nat

def int.pow (b : ) :   
| (int.of_nat n) := b ^ n
| (int.neg_succ_of_nat n) := 0

instance : has_pow int int := int.pow

@[simp]
def int.pow_of_nat (b : ) (e : ) : int.pow b e = int.of_nat (b ^ e) := rfl
-- 15:5: kernel failed to type check declaration 'int.pow_of_nat' this is usually due to a buggy tactic or a bug in the builtin elaborator
-- elaborated type:
--   ∀ (b e : ℕ), int.pow ↑b ↑e = int.of_nat (b ^ e)
-- elaborated value:
--   λ (b e : ℕ), rfl
-- nested exception message:
-- type mismatch at definition 'int.pow_of_nat', has type
--   ∀ (b e : ℕ), int.pow ↑b ↑e = int.pow ↑b ↑e
-- but is expected to have type
--   ∀ (b e : ℕ), int.pow ↑b ↑e = int.of_nat (b ^ e)

view this post on Zulip Scott Morrison (Oct 30 2019 at 21:27):

Looks like a bug to me... Hopefully someone who knows better will chime in soon.

view this post on Zulip Jason Gross (Oct 30 2019 at 21:28):

reported as https://github.com/leanprover-community/lean/issues/76

view this post on Zulip Chris Hughes (Oct 30 2019 at 22:06):

I don't think it is a bug. I wouldn't expect rfl to be able to prove that, you should have to induct on e first.

I don't think that's the usual error message, but I think that might be because it is a def rather than a lemma which would be more usual.

view this post on Zulip Jason Gross (Oct 30 2019 at 22:15):

If I do def bad : true = false := rfl, then I get a standard type error, without the extra words about it being possibly a bug

view this post on Zulip Reid Barton (Oct 30 2019 at 22:52):

It looks to me like the elaborator thought that int.pow_nat (int.of_nat b) e would reduce to int.of_nat (b ^ e), but if you #print int.pow_nat._main you can see it actually won't.

view this post on Zulip Reid Barton (Oct 30 2019 at 22:53):

Surprisingly to me and the elaborator (but apparently not to Chris) the equation compiler generated an outermost match on the second argument, not the first.

view this post on Zulip Jason Gross (Oct 30 2019 at 23:32):

If I get error: deep recursion was detected at 'expression equality test' (potential solution: increase stack space in your system), how do I increase stack space?

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:34):

It's a command line argument to lean

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:35):

but there is an adage that says that if you have to increase resource limits then you are probably doing something wrong

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:35):

I hope you don't actually expect that big example to work, it's a term 2^20 large

view this post on Zulip Jason Gross (Oct 30 2019 at 23:37):

@Mario Carneiro No, I'm getting this error on a different example, the big example was just creating something to exhibit the .... The thing I'm trying to do is in https://github.com/mit-plv/fiat-crypto/blob/6aaf03aed733d08ff124dffded9d8e2c7f4cc25a/src-lean/fiat_crypto.lean#L405, trying to get the norm_num tactic to finish when I change open ex to open ex2 (because ex was just a toy example; ex2 is the actual code I'm trying to work on)

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:39):

For these kinds of big CS problems, my recommendation is to make sure you have clean inputs to the tactics

view this post on Zulip Jason Gross (Oct 30 2019 at 23:39):

What do you mean by "clean inputs"?

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:39):

If you can, use natural number equalities and known functions only to norm_num

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:40):

give norm_num space to decide the problem and simplify the if statement afterward

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:40):

you may need to write a tactic to do this, the standard interactive mode chaining is probably not sufficient

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:41):

You can still use the existing tactics, but you are doing something specific by unfolding some functions, targeting a particular subterm for norm_num simplification, then going back to the simplifier and so on

view this post on Zulip Mario Carneiro (Oct 30 2019 at 23:42):

the norm_num front end handles this by just iterating norm_num1, simp, norm_num1, simp until stuff stops changing but that's only a heuristic

view this post on Zulip Jason Gross (Oct 30 2019 at 23:48):

I mean, iterating norm_num1, simp, ... seems not wrong, and in fact the call I have there produces the correct output for the smaller toy example. (I can't see if it produces correct output on a slightly larger example because I get the recursion depth error)

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:06):

So I looked through that fiat-crypto file, and what I see are 300 lines of definitions without any theorems, where almost every definition is marked for unfolding. This will explode in lean

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:07):

What you want are rewrites that unfold what matters, in the cases that matter. If you have a recursive definition (defined with *.rec), it should never be directly unfolded; instead you should have a theorem for the various constructors of the inductive type that you are recursing on

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:08):

What is the point of the let_in definition? It seems plainly useless

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:09):

Note that lean actually has a let construct

view this post on Zulip Jason Gross (Oct 31 2019 at 00:12):

@Mario Carneiro The let_in definition is one of the very few definitions that should never be unfolded

view this post on Zulip Jason Gross (Oct 31 2019 at 00:14):

After reduction/unfolding/rewriting, the only remaining definitions which are not unfolded should be *, +, %, /, and let_in

view this post on Zulip Jason Gross (Oct 31 2019 at 00:15):

I can change my definitions to not be in terms of recursors and instead be recursive themselves, but I don't see how that will fix anything. The times to unfold them are in fact when the underlying recursor is ready to be reduced

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:21):

The following definitions should not be simp: list.flat_map (aka list.bind), list.combine (aka list.zip), int.to_nat_bit(0/1) (the if statement should be a precondition), associational.eval, mul, definitely square, negate_snd, split, reduce, definitely reduce_square, carryterm, positional.from_associational, from_associational_cons, chained_carries, chained_carries_no_reduce.

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:22):

You don't necessarily need to change the definition (although using the equation compiler will do some of these things automatically for you), but you should add equational lemmas in the cases where you want the definition to unfold. Asking everything to unfold all at once is asking for trouble

view this post on Zulip Jason Gross (Oct 31 2019 at 00:25):

Wait, why should list.combine not be simp? It's just there so that I could make code translation easier, it literally just unfolds to list.zip (which I don't touch the flags of). from_associational_cons is telling from_associational to reduce in as close a match to the case where it should that I can get (in the case where it's applied to a concrete list)

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:25):

For example:

open prod

@[simp]
def associational.eval (p : list ( × )) :  :=
  list.foldr (λ x y, x + y) 0 (list.map (λ p, fst p * snd p) p)

should be

def associational.eval (p : list ( × )) :  :=
  list.foldr (λ x y, x + y) 0 (list.map (λ p, fst p * snd p) p)

@[simp] theorem associational.eval_nil : associational.eval [] = 0 := rfl
@[simp] theorem associational.eval_cons (a b l) :
  associational.eval ((a, b) :: l) = a * b + associational.eval l := rfl

view this post on Zulip Jason Gross (Oct 31 2019 at 00:26):

Sure. Though I will note that I don't use associational.eval anywhere right now, so not unfolding it is not a high priority

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:27):

or

@[simp] def associational.eval : list ( × )  
| [] := 0
| ((a, b) :: l) := a * b + associational.eval l

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:27):

It's an example; I can demonstrate on something else if you like

view this post on Zulip Jason Gross (Oct 31 2019 at 00:27):

Of the ones you listed, I use list.flat_map, list.combine, mul, split, reduce, carryterm, positional.from_associational, and chained_carries

view this post on Zulip Jason Gross (Oct 31 2019 at 00:30):

@Mario Carneiro Could you demonstrate on reduce (or split)?

view this post on Zulip Jason Gross (Oct 31 2019 at 00:31):

I'd also be interested in seeing carryterm

view this post on Zulip Jason Gross (Oct 31 2019 at 00:31):

reduce because I don't see how to write a simplification lemma for it; carryterm because the conditions under which it should reduce are complicated (namely, when fst t and w are numerals/closed terms)

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:36):

open prod
def let_in {A B : Type*} (x : A) (f : A  B) := f x

def associational.mul (p q : list ( × )) : list ( × ) := sorry

def associational.split (s : ) (p : list ( × )) : list ( × ) × list ( × ) :=
let (a, b) := list.partition (λ t, (fst t) % s = 0) p in
(b, list.map (λ t, (fst t / s, snd t)) a)

@[simp] theorem associational.split_val {s : } {p : list ( × )} {a b}
  (h : list.partition (λ t, (prod.fst t) % s = 0) p = (a, b)) :
  associational.split s p = (b, list.map (λ t, (fst t / s, snd t)) a) :=
by rw [associational.split, h, associational.split]

def associational.reduce (s c p) : list ( × ) :=
let (a, b) := associational.split s p in
a ++ associational.mul c b

@[simp] theorem associational.reduce_val (s c p) {a b}
  (h : associational.split s p = (a, b)) :
  associational.reduce s c p = a ++ associational.mul c b :=
by rw [associational.reduce, h, associational.reduce]

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:39):

def associational.carryterm (w fw:) (t: × ) :=
  if (fst t = w)
  then let_in (snd t)         (λ t2,
       let_in (t2 / fw)       (λ d2,
       let_in (t2 % fw) (λ m2,
       [(w * fw, d2), (w,m2)])))
  else [t]

@[simp] theorem associational.carryterm_pos (w fw b) :
  associational.carryterm w fw (w, b) =
  let_in b               (λ t2,
  let_in (t2 / fw)       (λ d2,
  let_in (t2 % fw) (λ m2,
  [(w * fw, d2), (w,m2)]))) := if_pos rfl

@[simp] theorem associational.carryterm_neg {w fw a b}
  (h : a  w) : associational.carryterm w fw (a, b) = [(a, b)] := if_neg h

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:41):

The basic idea is to have all arguments to the functions be in weak head normal form (i.e. for a list (Z x Z) it should be an empty list or a cons of a pair), and additionally when there are destructuring lets or other pattern matches inside the function the results of these should be hypotheses

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:42):

lean's equation compiler gives you something similar with an auxiliary function; if you print the definition of associational.split you will see that the destructuring let was done by creating an auxiliary that is defined by pattern matching

view this post on Zulip Jason Gross (Oct 31 2019 at 00:43):

And then how do I make use of these? Do I interleave "prove side-conditions with refl with simp for split_val? And it looks like rewriting with associational.carryterm_pos is incompatible with rewriting with associational.carryterm_neg; how do I get lean to pick the right one to rewrite with and prove the side-condition automatically?

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:43):

simp will do this

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:44):

But I should admit that lean has for a long time needed a tactic like Coq's cbv, for just doing evaluations like this

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:46):

simp uses an auxiliary side condition discharger (that is by default simp to true) for using conditional rewrite lemmas

view this post on Zulip Kevin Buzzard (Oct 31 2019 at 00:46):

What does CBV stand for?

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:47):

norm_num uses norm_num as the simp discharger, so it should be able to do the numeric part even inside if conditions and such

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:47):

call by value

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:47):

there is also cbn for call by name

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:47):

it refers to the order of evaluation. It's basically treating terms as a functional program and evaluating functions according to their definitions

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:48):

which is what rfl does already, but rfl has to go to completion while the hypothetical cbv tactic would just stop when it gets stuck

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:48):

right now people have to write mile-long simp invocations unfolding everything in sight

view this post on Zulip Mario Carneiro (Oct 31 2019 at 00:49):

or use carefully designed simp lemmas like the ones I've given above to guide the evaluation

view this post on Zulip Jason Gross (Oct 31 2019 at 01:09):

@Mario Carneiro if I try that, rw [associational.split_val] gives rewrite tactic failed, motive is not type correct and nested exception message: check failed, application type mismatch (use 'set_option trace.check true' for additional details)

view this post on Zulip Mario Carneiro (Oct 31 2019 at 01:09):

Are you rewriting in an if statement?

view this post on Zulip Jason Gross (Oct 31 2019 at 01:10):

Yes

view this post on Zulip Mario Carneiro (Oct 31 2019 at 01:10):

If you use the suggested approach, you should never have to see an if statement, but you can also use simp in these situations to rewrite and also fix the dependent decidability argument

view this post on Zulip Jason Gross (Oct 31 2019 at 01:14):

Also, associational.carryterm_neg doesn't seem to be triggering when the location to rewrite is under binders?

view this post on Zulip Jason Gross (Oct 31 2019 at 01:26):

I am not sure if this strategy is going to work; it seems that norm_num [lem1 lems] fails to handle cases where rw [lem1], norm_num [lems], norm_num [lems] works, and rw doesn't really work under binders.

import tactic.norm_num
open prod

universe u

@[simp]
def list.nth_default {A : Type u} (default : A) :  (ls : list A) (n : ), A
| []        _             := default
| (x :: xs) 0             := x
| (x :: xs) (nat.succ n') := list.nth_default xs n'


def associational.split (s : ) (p : list ( × )) : list ( × ) × list ( × ) :=
  let (a, b) := list.partition (λ t, (fst t) % s = 0) p in
  (b, list.map (λ t, (fst t / s, snd t)) a)

@[simp] theorem associational.split_val {s : } {p : list ( × )} {a b}
  (h : list.partition (λ t, (prod.fst t) % s = 0) p = (a, b)) :
  associational.split s p = (b, list.map (λ t, (fst t / s, snd t)) a) :=
by rw [associational.split, h, associational.split]


example (f g : list ) : (associational.split 65536 [(1, list.nth_default 0 f 0 * list.nth_default 0 g 0)]).snd = [] :=
begin
  rw [associational.split_val], norm_num [associational.split_val, (), list.filter], norm_num [associational.split_val, (), list.filter]
end

example (f g : list ) : (associational.split 65536 [(1, list.nth_default 0 f 0 * list.nth_default 0 g 0)]).snd = [] :=
begin
  norm_num [associational.split_val, (), list.filter]
-- 30:3: norm_num failed to simplify
-- state:
-- f g : list ℤ
-- ⊢ (associational.split 65536 [(1, list.nth_default 0 f 0 * list.nth_default 0 g 0)]).snd = list.nil
end

What's going on here?

view this post on Zulip Mario Carneiro (Oct 31 2019 at 01:41):

rw doesn't work under binders, simp does

view this post on Zulip Mario Carneiro (Oct 31 2019 at 02:03):

@Jason Gross hm, you may be right. This works:

@[simp] def associational.split (s : ) (p : list ( × )) : list ( × ) × list ( × ) :=
  let (a, b) := list.partition (λ t, (fst t) % s = 0) p in
  (b, list.map (λ t, (fst t / s, snd t)) a)

example (f g : list ) : (associational.split 65536 [(1, list.nth_default 0 f 0 * list.nth_default 0 g 0)]).snd = [] :=
begin
  simp [associational.split, list.filter], norm_num1, simp,
end

I've gone back to simp directly with the definition, but keeping the destructuring let, which prevents the unfolding from getting out of hand.

I should more seriously consider writing some equivalent to cbv that will do all of these things in the right order

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:24):

@Jason Gross I managed to get your original ex2 problem to compute to a value with a few modifications: https://gist.github.com/digama0/7649577d7c8af881cdbad50f9e84d81f

view this post on Zulip Jason Gross (Oct 31 2019 at 05:31):

@Mario Carneiro Thanks!

-def let_in {A : Type u} {B : Type v} (x : A) (f : A → B) := f x
+@[simp] def let_in {A : Type u} {B : Type v} (x : A) (f : A → B) := f x

Uh, it's pretty important to not make this change; it results in ~exponential blowup, and in some of the examples even larger than this one, it becomes even more of a problem. Is it essential to your way of making things work?

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:32):

I don't think so, it was mostly to get it out of the way for the other changes. A suitable set of other simp lemmas about let_in should suffice

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:32):

Lean does internally deduplicate expressions though, so it shouldn't cause exponential blowup

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:33):

basically, your approach is interfering with lean's own approach to the same problem

view this post on Zulip Jason Gross (Oct 31 2019 at 05:34):

The issue is that the goal is to generate C code, eventually, and we don't want exponential blow-up in the C code output, so we need to not unfold let_in. This is what all of the let_in.lift* lemmas at the bottom are about

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:35):

In that case, why is let_in not a constructor?

view this post on Zulip Jason Gross (Oct 31 2019 at 05:36):

Because I didn't want to re-write a bunch of code to be in a monad

view this post on Zulip Jason Gross (Oct 31 2019 at 05:36):

But, sure, you could make it a constructor, and sprinkle bind everywhere

view this post on Zulip Jason Gross (Oct 31 2019 at 05:36):

(But then you also need a way to do list (M T) -> M (list T), etc)

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:37):

The thing is that you are also trying to compute with this in lean, and in that context the let_in doesn't make any sense

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:38):

And you can't compute a C code expression this way because let_in would be reduced away

view this post on Zulip Jason Gross (Oct 31 2019 at 05:38):

The final step to get to C would be reifying or otherwise pretty-printing the code

view this post on Zulip Jason Gross (Oct 31 2019 at 05:39):

-  def positional.to_associational (n:ℕ) (xs:list ℤ) : list (ℤ × ℤ)
-    := list.combine (list.map weight (list.seq 0 n)) xs
+  def positional.to_associational (n:ℕ) (xs:list ℤ) : list (ℕ × ℤ)
+    := list.enum xs

This seems wrong. Did you deliberately remove weight here, or was it an oversight?

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:39):

the removal of weight was an oversight

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:39):

I wasn't sure about whether the removal of n was correct either

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:40):

But if n is much larger than xs the original approach has a lot of unnecessary computation

view this post on Zulip Jason Gross (Oct 31 2019 at 05:41):

n is always equal to the length of xs

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:41):

In that case I would want to have just one loop instead of two here

view this post on Zulip Jason Gross (Oct 31 2019 at 05:41):

Sure, that seems fine

view this post on Zulip Jason Gross (Oct 31 2019 at 05:42):

Also, how long should I expect this to take? The code you gave me has already been running for 14 minutes

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:42):

my test ran 7 minutes

view this post on Zulip Jason Gross (Oct 31 2019 at 05:43):

If I pass --tstack=1000000, does that make it slower?

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:43):

I doubt it

view this post on Zulip Jason Gross (Oct 31 2019 at 05:43):

Maybe your machine is more than 2x as fast as mine?

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:44):

let me fix the bugs and try again to make sure I posted the right file

view this post on Zulip Jason Gross (Oct 31 2019 at 05:45):

(Seems doubtful that you're twice as fast as me; my cpu is 3.6 GHz...)

view this post on Zulip Jason Gross (Oct 31 2019 at 05:46):

What does by exact _match l do in | (a::l) := positional.carry_reduce n s c a (by exact _match l)? (What's _match, and why are you doing it this way?)

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:53):

Unfortunately lean does not have Coq's fix constructor for making a recursive definition in the middle of a term. It has match for invoking the equation compiler, but it doesn't expose the name of the recursive function so you can make a recursive call. However it is exposed in tactics with the name _match

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:54):

An equivalent approach would be:

    @[simp] def positional.chained_carries_aux (n s c p) : list nat  list 
    | [] := p
    | (a::l) := positional.carry_reduce n s c a (positional.chained_carries_aux l)

    @[simp] def positional.chained_carries (n s c p) (idxs : list nat) :=
    positional.chained_carries_aux n s c p (list.reverse idxs)

view this post on Zulip Reid Barton (Oct 31 2019 at 05:56):

It's really annoying too when apply notices that this funny _match thing has the same type as the goal (imagine that)

view this post on Zulip Reid Barton (Oct 31 2019 at 05:56):

Er, maybe not apply but things that try assumption

view this post on Zulip Mario Carneiro (Oct 31 2019 at 05:58):

oh, I think I know what might be the difference: when I first tested it, I ran the norm_num invocation with carry_mulmod ... = sorry, and it finished after 7 minutes with the goal [0, 0, 0, 0, 0] = sorry. The version I put on the gist has the [0,0,0,0,0] edited in, which means that this also includes the kernel typechecking time

view this post on Zulip Jason Gross (Oct 31 2019 at 06:41):

If it finishes with [0,0,0,0,0], that's a bug (perhaps the removal of weight that I mentioned?). It's not supposed to reduce to a numeral, it's supposed to reduce to a bunch of let_ins expressing arithmetic about elements of f and g, followed by a list of bound variables

view this post on Zulip Mario Carneiro (Oct 31 2019 at 06:42):

When I take out the let_in simplification, it blocks on a function that takes a list, being passed a let_in applied to a list literal

view this post on Zulip Mario Carneiro (Oct 31 2019 at 07:02):

Also, for the record this looks to be a tad bit abusive of simp and regular functions. I have a better idea of what you are trying to do now, and I think that all of these functions should be tactics. They will run a lot faster, and you can still produce proofs along the way

view this post on Zulip Jason Gross (Oct 31 2019 at 19:04):

@Mario Carneiro Indeed, it blocks on a function taking a list, and that is what the lemmas like let_in.lift_map are for, to unblock reduction without inlining things

view this post on Zulip Jason Gross (Oct 31 2019 at 19:05):

Which functions should be tactics? The definitions on lists, or the reduction and let-lifting?

view this post on Zulip Mario Carneiro (Nov 01 2019 at 03:54):

@Jason Gross It's not quite clear to me how many of the functions on lists should be converted to tactics, but the basic idea would be to have all the stuff you actually want in the output (notably the let_in constructs) as exprs, with most of the list functions being functions that manipulate lists of exprs and such, so that you can evaluate them in the VM instead of all the simping.

What isn't clear to me is what you want to assert about the resulting let lifted expression. As it is (assuming the simp stuff can be made to work), you end up with a proof that asserts something like carry_mulmod ... = let_in (f 1 * g 1) (\lam x, let_in ...), but as a theorem this doesn't appear particularly valuable since carry_mulmod is just a function that computes the thing on the right. Presumably you have some semantics about mulmod that you actually care about, and this should be what you want to prove a relation to. Or maybe you don't want to prove it is anything in particular, you just want the expression on the right, in which case it can be done a lot faster in the VM.

view this post on Zulip Jason Gross (Nov 01 2019 at 03:59):

@Mario Carneiro The theorem I want to prove is that associational.eval (positional.to_associational (carry_mulmod f g)) = (eval f * eval g) % (s - associational.eval c). (Where def asociational.eval (p) := list.foldr (+) 0 (list.map (\lambda (w, v), w * v) p).) Each of the list definitions has a corresponding lemma about what it does under eval, c.f. https://github.com/mit-plv/fiat-crypto/blob/master/src/Arithmetic/Core.v

view this post on Zulip Jason Gross (Nov 01 2019 at 04:01):

Then I can combine this theorem with the carry_mulmod ... = let_in ... theorem to get a theorem about the evaluation of the final expression

view this post on Zulip Mario Carneiro (Nov 01 2019 at 08:05):

@Jason Gross I don't think I can help you with this one. I've tried several methods, but I think lean's kernel evaluation just isn't up to the task - it's abysmally slow at just about every approach to this that doesn't involve a complete rewrite. (It doesn't help that the algorithm itself is not super efficient; I can see that this would probably evaluate well enough in Coq but the Coq kernel evaluator is more efficient than lean's.) The fact that it's not completely a refl proof but has embedded subproofs makes this evaluation significantly more elaborate than it otherwise would be, and the constant allocation of new variables and lifting the term is also a performance bottleneck. This is possibly a good test case for lean 4.

view this post on Zulip Jason Gross (Nov 01 2019 at 08:31):

I appreciate all the help you've provided; thank you. And feel free to take it as a test case for lean 4. I will note that Coq only performs adequately if I rewrite the entire thing in CPS (so no term lifting needs to be done to reduce), make all the things that don't get unfolded axioms, and then run it in the vm. Coq's rewriting tactics perform more slowly than Lean's (by a factor of 6, in the one case I could test). Getting reasonable performance on this benchmark has been my PhD project for the last year or two, sort-of, and required writing a reflective rewriter mixed with NbE to be run in vm compute, and I'm currently in the process of writing this up in a paper for PLDI

view this post on Zulip Mario Carneiro (Nov 01 2019 at 09:05):

I updated the gist with my latest version: https://gist.github.com/digama0/7649577d7c8af881cdbad50f9e84d81f

I put it in a monad after all:

inductive let_bound (α : Type*)
| base : α  let_bound
| dlet :   (  let_bound)  let_bound
| mlet {β : Type} : β  (β  let_bound)  let_bound

The meaning is that dlet is the constructor for let_in, and mlet is a subgoal that should be solved by norm_num. In theory, you should be able to take the (carry_mulmod ...).eval term, and then successively normalize it (by whnf) to (mlet x f).eval which rewrites to (f y).eval after figuring out x ~> y by other tactics, and (dlet x f).eval which rewrites to let_in x (\lam a, (f a).eval)and work continues inside the lambda.

view this post on Zulip Mario Carneiro (Nov 01 2019 at 09:07):

In practice, it seems to take about 1 sec per let binding, plus my tactics for doing the reduction are super janky

view this post on Zulip Jason Gross (Nov 02 2019 at 04:02):

@Mario Carneiro Neat, thanks! Is that 1 second per internal let-binder (including mlet), or 1 second per emitted dlet? I will note that real examples range from a couple dozen dlets at the small end to about 3800 dlets (possibly more for some of the code we don't build routinely) at the large end.

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:05):

I think what I was seeing was mlets. In ex2 there are about a dozen of them (solving stupidly large goals like to_bool (1 % <big number> = 0)) before you get to the first dlet

view this post on Zulip Jason Gross (Nov 02 2019 at 04:06):

Ah, yes, there are a lot of those

view this post on Zulip Jason Gross (Nov 02 2019 at 04:16):

solving stupidly large goals like to_bool (1 % <big number> = 0)

Shouldn't solving this be fast/easy, because 1 % <big number> is always 1, and the division computation should be relatively fast because the numerator is small?

view this post on Zulip Jason Gross (Nov 02 2019 at 04:22):

@Mario Carneiro I tried running your code, but it seems to fail with ~no progress after 77 seconds?

$ /usr/bin/time -f "$@ (real: %e, user: %U, sys: %S, mem: %M ko)" lean fiat-test.lean
to_bool (weight machine_wordsize 1 0 * weight machine_wordsize 1 0 % s = 0)
2 goals
f g : ℕ → ℤ,
a : ℤ
⊢ let_bound.eval
      (let_bound.bind (positional.carry_reduce (… 1) n s c 1)
         ((λ (x : ℤ), let_bound.bind (… s c 0) ((λ (x : ℤ), let_bound.map … (… …)) x)) a)) =
    ?m_1 a

f g : ℕ → ℤ
⊢ ℤ → list ℤ
to_bool (weight machine_wordsize 1 0 = weight machine_wordsize 1 0)
f g : ℕ → ℤ,
a a_1 : ℤ
⊢ let_bound.eval
      (let_bound.bind (positional.carry_reduce (… 1) n s c 1)
         ((λ (x : ℤ),
             let_bound.bind (λ (a : list ℤ), let x : list … := … a in … …)
               ((λ (x : ℤ), let_bound.bind … (… x)) x))
            a_1)) =
    ?m_1 a_1
f g : ℕ → ℤ,
a a_1 a_2 : ℤ
⊢ let_bound.eval
      (let_bound.bind (positional.carry_reduce (… 1) n s c 1)
         ((λ (x : ℤ),
             let_bound.bind (λ (a : list ℤ), let x : list … := … a in … …)
               ((λ (x : ℤ), let_bound.bind … (… x)) x))
            a_2)) =
    ?m_1 a_2
/home/jgross/Documents/repos/fiat-lean-test/fiat-test.lean:345:2: error: convert tactic failed, there are unsolved goals
state:
f g : ℕ → ℤ,
a a_1 a_2 : ℤ
⊢ let_bound.eval
      (let_bound.bind (positional.carry_reduce (… 1) n s c 1)
         ((λ (x : ℤ),
             let_bound.bind (λ (a : list ℤ), let x : list … := … a in … …)
               ((λ (x : ℤ), let_bound.bind … (… x)) x))
            a_2)) =
    ?m_1 a_2
Command exited with non-zero status 1
 (real: 76.88, user: 76.73, sys: 0.24, mem: 396720 ko)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:22):

it probably doesn't work

view this post on Zulip Jason Gross (Nov 02 2019 at 04:22):

(Maybe I am misreading the output, though...)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:23):

if you can find some use for the code, great, but it comes with no warranty

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:24):

the tactic itself is extremely experimental

view this post on Zulip Jason Gross (Nov 02 2019 at 04:24):

Okay. I think I'm not yet sufficiently experienced with Lean to extract value from the tactic code, and I've satisfied my curiosity about how good Lean's features are out-of-the-box at solving this sort of goal.

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:24):

it got a bit hard to test because everything takes forever

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:25):

This is definitely not something anyone has attempted to do before in lean

view this post on Zulip Jason Gross (Nov 02 2019 at 04:25):

it got a bit hard to test because everything takes forever

That's the story of my PhD. I've probably spent 80% of my time trying to figure out how to work around performance issues in Coq

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:26):

My instincts say "fix the algorithm"

view this post on Zulip Jason Gross (Nov 02 2019 at 04:26):

What do you mean "fix the algorithm"?

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:26):

There is a ton of list manipulation code in here that seems to be unnecessary

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:27):

I mean, if it's a benchmark then that's fine, but I think you can obtain equivalent results with another approach that doesn't involve all these let bindings

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:28):

and what's with all this back and forth between positional and associational representations?

view this post on Zulip Jason Gross (Nov 02 2019 at 04:29):

The ultimate goal is to produce code like this: https://github.com/mit-plv/fiat-crypto/blob/5a51b7a2f9fc8aad46963f0d9bbe64047de0704f/curve25519_64.c#L96-L154

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:31):

I would write a tactic that produces that, and a simultaneously proof of the semantics of it

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:32):

Z would never show up in the algorithm

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:32):

(except in the tactic code itself)

view this post on Zulip Jason Gross (Nov 02 2019 at 04:34):

The back-and-forth between positional and associational is because some algorithms are easy to express and prove in the associational representation (addition of numbers is just list concatenation, multiplication is just all the ways of combining pairs of elements of the lists with *), while positional is the format that is actually used to store the numbers in memory / transmit them on the wire. But you're right, there's a lot of unnecessary back-and-forth in chained_carries, which could probably benefit from being moved to associational.

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:36):

The point is to separate the parts of the algorithm that actually need to be executed, and the parts that are actually the output (creating the list of let bindings)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:36):

the part that gets executed can happen in the VM (fast and untrusted), and the part that is output is term creation with a proof of correctness

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:37):

Right now everything is happening as term manipulation, so it's all slow

view this post on Zulip Jason Gross (Nov 02 2019 at 04:40):

Maybe I don't understand what you mean by a tactic that produces both the term and the proof. e.g., what would this look like for associational.carryterm, whose spec is associational.eval (associational.carryterm w fw t) = associational.eval [t] (Coq proof here)

view this post on Zulip Jason Gross (Nov 02 2019 at 04:41):

(The proof is pretty simple: it's basically just the spec of div and mod, plus ring)

view this post on Zulip Jason Gross (Nov 02 2019 at 04:43):

Do you mean something like, a tactic that builds a sigma type { ct : list (Z * Z) | associational.eval ct = associational.eval [t] }?

view this post on Zulip Jason Gross (Nov 02 2019 at 04:43):

or, er, maybe it is all inside the let monad

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:44):

You have a tactic called carryterm (...) : tactic (term x expr), which is given some inputs and produces a pair of a term and a proof of associational.eval t' = associational.eval [t] (where t' is the reification of the returned term)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:46):

yes, you could also view it as a sigma type, although you want ct here to be a concrete list, not an arbitrary term of type list (Z * Z)

view this post on Zulip Jason Gross (Nov 02 2019 at 04:46):

Yes, a concrete list, but it's under let binders

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:47):

which is why it is returned as a term (which is some inductive type you define that specifies the valid constructions, in this case a list under let binders)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:47):

I suspect that you actually should be keeping the let binders on the side though; that is, you have some growing context of let binders and your monad allows you to add to it

view this post on Zulip Jason Gross (Nov 02 2019 at 04:48):

Hm, but the proofs are invalid if you don't know the values of the binders. I get the evaluation for the proofs looks things up from the binders on the side?

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:49):

Yes, you would be passing it as another argument to eval in that case

view this post on Zulip Jason Gross (Nov 02 2019 at 04:49):

Okay, so I see how I could produce the term, but I don't see how producing the proof on the fly every time I call carryterm is going to be any faster. It seems like it can only possibly be slower, because now not only are you computing equality of list manipulation, you're also computing equality of associational.eval

view this post on Zulip Jason Gross (Nov 02 2019 at 04:51):

Oh, I see, at least for carryterm, you don't need to worry about what the bool computes you, you just produce a proof of one side or the other

view this post on Zulip Jason Gross (Nov 02 2019 at 04:52):

(I still think the proof is going to be expensive here, because you're calling ring)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:52):

Both parts are produced by application of theorems like those I mentioned earlier. You aren't "computing" anything in the DTT sense; you are applying theorems that build up eval equalities about these reified terms

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:52):

You actually don't need to call ring at all this way

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:52):

That's the main benefit

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:53):

If you have something like if a % s = 0 then ... else ... in the algorithm, that's fine, it runs in the VM and uses a bignum library

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:55):

The only reason you need to run norm_num is if you needed that fact a % s = 0 in order to produce the correctness proof, but with this approach it's easy to run it and provide the input where it is needed

view this post on Zulip Jason Gross (Nov 02 2019 at 04:57):

Hm, this is interesting, I'll have to think more about this approach

view this post on Zulip Jason Gross (Nov 02 2019 at 04:58):

(And, indeed, in associational.split, we need a proof of a % s = 0 for the then branch, but don't need to know anything in the else branch)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 04:59):

Additionally, you can easily shortcut the computation by applying a theorem with the alternate hypothesis a = 0, or a = s, or a = k * s where you precompute what k should be

view this post on Zulip Jason Gross (Nov 02 2019 at 05:04):

Presumably I still need norm_num to prove a = k * s, though, right? Because of https://webcache.googleusercontent.com/search?q=cache:tVeSAlPEQN4J:https://github.com/leanprover/lean/issues/1799+&cd=2&hl=en&ct=clnk&gl=us

view this post on Zulip Jason Gross (Nov 02 2019 at 05:05):

(Did someone delete all the issues on leanprover/lean? There's no issue page anymore, and all the pre-existing issues give 404 now...)

view this post on Zulip Mario Carneiro (Nov 02 2019 at 05:17):

What the... It appears Leo simplified the readme and deleted the entire issues page for leanprover/lean. I didn't even know that was possible, but I hope we can get the history migrated to the community version

view this post on Zulip Mario Carneiro (Nov 02 2019 at 05:21):

Yes, you would want to use norm_num to prove the a = k * s side goal.

view this post on Zulip Mario Carneiro (Nov 02 2019 at 05:23):

Indeed, the approach I am describing is basically what norm_num does itself, for arithmetic goals

view this post on Zulip Jason Gross (Nov 02 2019 at 05:30):

Is there any chance I can get Lean to manage the context for me, or do I have to do it myself and reason about, e.g., uniqueness of names and context-lookup, etc?

view this post on Zulip Jason Gross (Nov 02 2019 at 05:32):

There's a checkbox under "options" of a github repository to enable/disable issues. I could believe that when you disable issues, github just makes them inaccessible to non-admins or something. (I could also believe it deletes them)

view this post on Zulip Jason Gross (Nov 02 2019 at 05:34):

Yeah, when you uncheck the issues box, github makes all issues be 404s. When you recheck it, they all come back

view this post on Zulip Bryan Gin-ge Chen (Nov 02 2019 at 05:34):

Indeed, according to this page re-enabling the issues would make the old ones accessible again. I could only find this page on migrating single open issues, and it didn't look too promising. Maybe github support could work some magic though.

view this post on Zulip Jason Gross (Nov 02 2019 at 05:35):

It's definitely possible to mass-migrate issues, though you might need to write a tool to do it using the github api (and get Leo to re-enable issues temporarily)

view this post on Zulip Jason Gross (Nov 02 2019 at 05:35):

Coq migrated all of it's issues from bugzilla to github, mostly preserving issue numbers (but they all show as authored by coqbot, unfortunately)

view this post on Zulip Jason Gross (Nov 02 2019 at 05:37):

https://github.com/IQAndreas/github-issues-import

view this post on Zulip Jason Gross (Nov 02 2019 at 05:39):

Also, http://www.alexhadik.com/blog/2016/5/26/migrating-github-repositories-with-gitmover

view this post on Zulip Andrew Ashworth (Nov 02 2019 at 16:03):

you're going to want my fork: https://github.com/alashworth/github-issues-import

view this post on Zulip Andrew Ashworth (Nov 02 2019 at 16:03):

also you will need to speak to github admin to whitelist your account, otherwise you'll get autobanned for spamming

view this post on Zulip Andrew Ashworth (Nov 02 2019 at 16:03):

(went through this in march)

view this post on Zulip Gihan Marasingha (Nov 10 2019 at 19:11):

(deleted)

view this post on Zulip Gihan Marasingha (Nov 10 2019 at 19:12):

(deleted)

view this post on Zulip Reuben Rowe (Nov 16 2019 at 17:35):

If I have an instance denumerable α and two values x y : α, is there a way to be able to write if x = y then ... rather than if (encodable.encode x) = (encodable.encode y) then .... That is, how to I get Lean to infer decidable (x = y)?

view this post on Zulip Mario Carneiro (Nov 16 2019 at 17:38):

you want to assume decidable_eq A too

view this post on Zulip Reuben Rowe (Nov 16 2019 at 17:40):

Great, thanks - but it seemed to me that this can be derived from denumerability. Why should I have to assume it separately?

view this post on Zulip Mario Carneiro (Nov 16 2019 at 17:41):

because the implementation might be different

view this post on Zulip Reuben Rowe (Nov 16 2019 at 17:41):

Derived from denumerability, given that equality on \Nat is decidable

view this post on Zulip Mario Carneiro (Nov 16 2019 at 17:41):

it's not usually the best way to decide equality

view this post on Zulip Reuben Rowe (Nov 16 2019 at 17:47):

OK, sure. Thanks!

view this post on Zulip Bryan Gin-ge Chen (Dec 30 2019 at 18:40):

How does rcases / rintro with rfl in the pattern work? I couldn't find it documented anywhere.

view this post on Zulip Johan Commelin (Dec 30 2019 at 18:49):

I you have some expression of the form x = a, then the rfl pattern works as if you just wrote h, and followed the rcases/rintro with a subst h.

view this post on Zulip Greg Langmead (Jan 08 2020 at 23:15):

Any tips on defining the unit sphere in Euclidean space? I'm using @Sebastien Gouezel 's definition def euclidean_space (n : ℕ) : Type := (fin n → ℝ) and can't figure out how to form the summation of the squares def unit_sphere (n : ℕ) := { x : euclidean_space n // ...}

view this post on Zulip Kevin Buzzard (Jan 08 2020 at 23:18):

import data.real.basic

def euclidean_space (n : ) : Type := (fin n  )

def unit_sphere (n : ) := { x : euclidean_space n // finset.sum finset.univ (λ i, (x i) ^ 2) = 1}

view this post on Zulip Kevin Buzzard (Jan 08 2020 at 23:19):

Maybe def unit_sphere (n : ℕ) := { x : euclidean_space n // finset.univ.sum (λ i, (x i) ^ 2) = 1} is a bit nicer.

view this post on Zulip Kevin Buzzard (Jan 08 2020 at 23:22):

#check @finset.sum
/-
finset.sum : Π {α : Type u_1} {β : Type u_2} [_inst_1 : add_comm_monoid β], finset α → (α → β) → β
-/

finset.sum eats a finite subset of alpha, and a function from alpha to a commutative monoid beta, and spits out the sum of this function over the given finite subset of alpha.

view this post on Zulip Kevin Buzzard (Jan 08 2020 at 23:26):

finset.univ is all of the set alpha (which Lean figures out must be fin n by "unification"), and Lean also figures out that alpha is a finite type (by "type class inference")

view this post on Zulip Nicholas Talin (Jan 08 2020 at 23:59):

What would be the best introductory book on analysis if I wanted to use Lean to formalize its statements and solve exercises along the way?

view this post on Zulip Greg Langmead (Jan 09 2020 at 01:11):

Thank you Kevin, that works great. I will need to stare longer at finset.univ. Now I'll work towards proving these are smooth manifolds!

view this post on Zulip Yury G. Kudryashov (Jan 09 2020 at 01:17):

@Greg Langmead Would it be convenient to have the implicit function theorem first?

view this post on Zulip Yury G. Kudryashov (Jan 09 2020 at 01:19):

Then we would be able to prove that a smooth function defines a submanifold. Or you prefer to have some explicit set of charts (e.g., two stereographic projections)?

view this post on Zulip Greg Langmead (Jan 09 2020 at 01:38):

@Yury G. Kudryashov I'm planning on doing it both ways, i.e. with explicit charts, and then proving various more general things. I'm thinking along the lines of an introductory differential geometry text that is also an introduction to formalization.

view this post on Zulip Andrew Ashworth (Jan 09 2020 at 05:29):

@Nicholas Talin Several people have used Tao's Analysis 1 + 2; it's quite formal for an introductory text. You are on your own converting the lemmas and definitions to work with mathlib though, since it uses set theory as its foundations

view this post on Zulip Kevin Buzzard (Jan 09 2020 at 06:26):

I dunno about "on your own" -- I for one would be very happy to help. And set theory/type theory hopefully shouldn't make too much of a difference here. I've proved basic analysis results about series/sequences etc in Lean, I think @Kenny Lau proved Bolzano-Weierstrass somewhere, etc.

view this post on Zulip Yury G. Kudryashov (Jan 09 2020 at 23:22):

@Greg Langmead I have a branch with inverse function theorem (mostly done). I'm going to make a PR in a few days.

view this post on Zulip Spencer Peters (Jan 14 2020 at 21:18):

Hi everyone! I just got introduced to Lean through the natural number game, and I started playing around with writing up the first homework from a discrete math class I TA'd recently. In that homework, students were supposed to define a sudoku puzzle as a function f: {1, 2, ..., 9} x {1, 2, ..., 9} -> {1, 2, ..., 9}. So I defined the subtype

def nine : Type := {v :  // v < 9}

Now I have two questions. First, although I can coerce a subtype of nat to nat, I can't seem to coerce a "nine" to a nat. What I mean is that this works:

constant x : {v :  // v < 9}
#check (x:)

But this produces an error:

def nine : Type := {x :  // x < 9}
constant y : nine
#check (y:)

Is there a line I can add which will cause all the typeclass instances of {x : ℕ // x < 9} to carry over to the new type nine?
My second question has to do with sets in Lean. In our discrete math class obviously we work with sets, not inductive types. So I would like the students to be able to work with something like (edited, set nine changed to set nat)

def nine_set : set nat := {1, 2, 3, 4, 5, 6, 7, 8, 9}

But if I then try to define a function from nine_set to nine_set, I run into the issue that nine_set is not a Type! I'm guessing that there isn't any way around this, but I thought I'd ask.

view this post on Zulip Bryan Gin-ge Chen (Jan 14 2020 at 21:21):

Welcome! You might find this doc on "set-like objects" in mathlib useful. I'll take a look at the more detailed questions later if no one else has gotten to them.

view this post on Zulip Kevin Buzzard (Jan 14 2020 at 22:15):

We already have a type fin 9. You might be better off sticking with that.

You can add the coercion manually:

def nine : Type := {v :  // v < 9}

instance : has_coe nine  :=
⟨λ n, n.1

constant y : nine
#check (y : ) -- works

The switch from finite sets to types will be painful. I constantly tell the student that a term of type fin 9 is a pair consisting of a number and a proof, and eventually this will dawn on them.

view this post on Zulip Spencer Peters (Jan 14 2020 at 23:17):

Thanks Bryan! The mathlib doc was useful. And thank you Kevin! It's interesting that fin 9 also has no coercion to nat by default, e.g. the following doesn't work:

constant z : fin 9
#check (↑z : ℕ)

That the switch will be painful doesn't surprise me--I also had some difficulty wrapping my head around the definition of a subtype. For context, I want to improve an introductory class for computer science majors who don't, by and large, have any background in formal math. My goal is to use Lean to help students understand formal math via their familiarity with programming. In my experience, students understand what it means for code to compile/not compile, but they don't understand as clearly what it means for a proof to be valid/invalid. In principle, Lean seems like a great way to bridge the gap, although in practice I'm not sure owing to the overhead of things like sets vs. inductive types. I'm also interested in using Lean as (or as the basis for) an interactive development environment for proofs, as an alternative to pencil and paper or TeX.

view this post on Zulip Kevin Buzzard (Jan 14 2020 at 23:20):

Have you seen Avigad's Logic and proof? Perhaps his students are similar to yours? I usually deal with mathematicians so have different problems -- they might well have some idea what a proof is, but have never seen a functional language or type theory before.

view this post on Zulip Spencer Peters (Jan 15 2020 at 08:46):

Yes, thanks for the pointer! This curriculum is similar to what I'd like to teach, although I can't afford to spend quite as much time on natural deduction and logic. In the course I'm working from (https://courses.cs.cornell.edu/cs2800/wiki/index.php/CS_2800_Fall_2019), we have to quickly cover a lot of topics relevant to computer science, starting from sets, functions and relations. I'm hoping that I can set up something that will let students start working right away without detailed knowledge of the logical foundations (like the natural number game).

view this post on Zulip Kevin Buzzard (Jan 15 2020 at 12:38):

I did functions and relations in my course last term.Here are the example sheets:

https://github.com/ImperialCollegeLondon/M40001_lean

view this post on Zulip Kevin Buzzard (Jan 15 2020 at 13:34):

@Jason KY. have you formalised some of the lecture notes in some form? Maybe Spencer would be interested.

view this post on Zulip Jason KY. (Jan 15 2020 at 13:47):

Jason KY. have you formalised some of the lecture notes in some form? Maybe Spencer would be interested.

Emm, well I've formalised the first part of the intro module and am currently working on analysis but I've not written any comments for those parts.
They are all here if anyone is interested :)
https://github.com/JasonKYi/M4000x_LEAN_formalisation

view this post on Zulip Kevin Buzzard (Jan 15 2020 at 13:50):

Spencer -- feel free to build on this stuff if it's of any use to you. Jason is one of my undergraduates; he took my class.

view this post on Zulip Spencer Peters (Jan 15 2020 at 23:44):

Thank you! I'll dig into these. Much appreciated :)

view this post on Zulip Anton Lorenzen (Jan 16 2020 at 16:40):

Do you know how I can tell Lean that for c, d, e in Prop and c decidable, "c -> d" and "c -> ite c d e" are the same type? Or lift a value of the first type to a value of the second? (This is my first post here, so I hope this is the right place to ask that)

view this post on Zulip Joe (Jan 16 2020 at 17:04):

Both of them have the type Prop. I guess you want to prove the following?

lemma foo (c d e : Prop) [decidable c] : (c  d)  (c  if c then d else e) :=

view this post on Zulip Anton Lorenzen (Jan 16 2020 at 17:08):

@Joe Yes

view this post on Zulip Kevin Buzzard (Jan 16 2020 at 17:11):

It's called something like ifpos [edit: if_pos]

view this post on Zulip Joe (Jan 16 2020 at 17:17):

Can you use tactics?

lemma foo (c d e : Prop) [decidable c] : (c  d)  (c  if c then d else e) :=
iff.intro
  (λ h hc, by { rw if_pos hc, exact h hc })
  (λ h hc, by { have := h hc, rw if_pos hc at this, assumption })

view this post on Zulip Anton Lorenzen (Jan 16 2020 at 17:18):

Got this with if_pos. Looks good!

lemma foo (c d e : Prop) [decidable c] : (c → d) ↔ (c → if c then d else e) :=
  iff.intro (λ f c, eq.mp (eq.symm (if_pos c)) (f c)) (λ f c, eq.mp (if_pos c) (f c))

view this post on Zulip Greg Langmead (Jan 25 2020 at 19:48):

I'm having trouble working with continuous functions on subsets of euclidean space. I think I lack some idiom. The first proof below is working for all of ℝ but the second gives an error because it needs some sort of coercion maybe?

import geometry.manifold.real_instances

lemma certain_func_is_continuous : continuous (λ x:ℝ, 4 * (x:ℝ)) :=
begin
  apply continuous.mul _ _,
  apply_instance,
  exact continuous_const,
  exact continuous_id,
end

def real_gt_one := {x: ℝ | x > 1}

lemma certain_func_is_continuous_gtone : continuous (λ x:real_gt_one, 4 * (x:ℝ)) :=
begin
  apply continuous.mul _ _,
  apply_instance,
  exact continuous_const,
  exact continuous_id,
end

the error is

invalid type ascription, term has type
  continuous id
but is expected to have type
  continuous (λ (x : ↥real_gt_one), ↑x)

My short term goal is to define functions that are only continuous on the subset like 1/(1-x).

view this post on Zulip Alex J. Best (Jan 25 2020 at 19:58):

Your function is from real_gt_one to , is that what you want? In this case your function at the end is not id the identity function but rather coe the coercion from real_gt_one to .

view this post on Zulip Yury G. Kudryashov (Jan 25 2020 at 19:58):

I guess you need continuous_subtype_val

view this post on Zulip Alex J. Best (Jan 25 2020 at 19:58):

If you run dsimp before your last line lean simplifies your expression to show that the goal is continuous coe really.

view this post on Zulip Yury G. Kudryashov (Jan 25 2020 at 20:01):

BTW, I wonder if the following will work in most cases to automatically prove continuity: (1) mark many lemmas with @[continuity], and (2) make acontinuity tactic to be a shorthand for apply_rules [continuity].

view this post on Zulip Yury G. Kudryashov (Jan 25 2020 at 20:02):

I have no time do give it a try in the next week or two.

view this post on Zulip Kevin Buzzard (Jan 25 2020 at 20:09):

There was some talk about the continuity tactic in Pittsburgh

view this post on Zulip Greg Langmead (Jan 25 2020 at 20:39):

Thanks, dsimp and continuous_subtype_val helped. I am defining various real-valued functions so definitely want values in ℝ. Eventually I'll bring this back to stereographic projection which is my first mini-project.

With regard to making continuity easier to prove, it seems to me (disclaimer: a noob) that it's a heavy-handed paradigm to edit all the other files to mark various lemmas that might be useful. It feels like the wrong separation of concerns. I'm not sure what the alternative is, but is it possible to build up my own personal collections of often-used lemmas (and wildcard lemmas like "continuous*"), and have some tactic search among those?

view this post on Zulip Greg Langmead (Jan 25 2020 at 20:56):

To partially answer my own question, I see I can make a local attribute and add things to it per the apply_rules docs https://github.com/leanprover-community/mathlib/blob/master/docs/tactics.md.

view this post on Zulip Greg Langmead (Jan 25 2020 at 21:10):

To keep running with this, if I define my_continuity_lemmas : user_attribute then I can do apply_rules [my_continuity_lemmas] but this won't prove my new lemmas by itself, I also need other tactics like apply_instance. Can I package up apply_rules [my_continuity_lemmas] as a tactic apply_my_continuity_lemmas so I could then do chain [apply_instance, apply_my_continuity_lemmas]? I have a sinking feeling I'm starting to talk nonsense.

view this post on Zulip Yury G. Kudryashov (Jan 25 2020 at 22:58):

Yes, you can create your own attribute. I was talking about a way to handle this everywhere in mathlib.

view this post on Zulip Yury G. Kudryashov (Jan 25 2020 at 22:59):

@Kevin Buzzard Could you please tell me some details?

view this post on Zulip Kevin Buzzard (Jan 25 2020 at 23:03):

I don't understand things well enough to be able to say anything coherent.

view this post on Zulip Yury G. Kudryashov (Jan 25 2020 at 23:10):

Then you can tag one of those who discussed this.

view this post on Zulip Kevin Buzzard (Jan 25 2020 at 23:10):

@Reid Barton made some comments at some point...

view this post on Zulip Joe (Jan 25 2020 at 23:12):

I think that would work, except that tactics such as apply refine exact won't stop on the simplest cases. @Yury G. Kudryashov

view this post on Zulip Joe (Jan 25 2020 at 23:12):

Here is an example I discovered a long time ago, where using apply' continuous_tan' on continuous (λx, sin x) results in a timeout. The root of this problem is exact, so I guess there is nothing you can do. Though I think there must be a way to make things irreducible or something, so that unifying mismatched expressions can end quickly.

import analysis.complex.exponential
import tactic.basic
import tactic.tidy
import tactic.apply
import tactic.apply_fun

namespace real
variables {α : Type*} [topological_space α] {f : α  } (hf : continuous f)
include hf

lemma continuous_tan' (h : a, cos (f a)  0) : continuous (λa, tan (f a)) :=
show continuous ((tan  @subtype.val  (λx, (cos x)  0))  λa, f a, h a),
  from continuous.comp continuous_tan (continuous_subtype_mk _ hf)

end real

open real

lemma foo : continuous (λx, sin x) :=
begin
  have := @continuous_tan'  _ _ _ _,
  exact this,
  -- apply' this,
  -- refine this,
  -- apply this,
end

view this post on Zulip Reid Barton (Jan 25 2020 at 23:45):

Yes, probably a case of excessive (and fruitless) definitional unfolding.

view this post on Zulip Chris Hughes (Jan 25 2020 at 23:51):

You can just set tactic.apply to only unfold reducibles right?

view this post on Zulip Joe (Jan 26 2020 at 00:07):

I don't know if that would work because apply is bugged. Even applying continuous_sin' to continuous (λx, sin x) fails.

import analysis.complex.exponential
import tactic.apply

namespace real
variables {α : Type*} [topological_space α] {f : α  } (hf : continuous f)
include hf

lemma continuous_sin' : continuous (λa, sin (f a)) := sorry

end real

open real

lemma foo : continuous (λx, sin x) :=
begin
  apply continuous_sin',  -- fails
end

view this post on Zulip Chris Hughes (Jan 26 2020 at 00:09):

There's apply' which fixes the bug.

view this post on Zulip Joe (Jan 26 2020 at 00:09):

On the other hand, if you look at the source code of apply', it tries exact first:

private meta def retry_apply_aux : Π (e : expr) (cfg : apply_cfg), list (bool × name ×  expr)  tactic (list (name × expr))
| e cfg gs :=
focus1 (do {
     tgt : expr  target, t  infer_type e,
     unify t tgt,                             -- apply' is already stuck here
     exact e,
     gs'  get_goals,
     let r := reorder_goals gs cfg.new_goals,
     set_goals (gs' ++ r.map prod.snd),
     return r }) <|>
do (expr.pi n bi d b)  infer_type e >>= whnf | apply_core e cfg,  -- so it will never get here
   v  mk_meta_var d,
   let b := b.has_var,
   e  head_beta $ e v,
   retry_apply_aux e cfg ((b, n, v) :: gs)

view this post on Zulip Greg Langmead (Jan 26 2020 at 18:55):

@Yury G. Kudryashov I was suggesting that instead of sprinkling @[continuity] hints around mathlib, there could be one file with packages of continuity lemmas being exported under various names. That seems more general than deciding in a one-size-fits-all fashion at the point where the lemma is defined.

view this post on Zulip Greg Langmead (Jan 26 2020 at 18:58):

Now I'm trying to define continuity of a function of two variables and I can't get continuous_snd to work with my subset of ℝ×ℝ:

lemma certain_twovar_func_continuous : continuous (λx:real_gt_one × real_gt_one, (x.1:ℝ) * (1 - (x.2:ℝ)⁻¹)) :=
begin
  apply continuous.mul _ _,
  apply_instance,
  sorry, -- writing "apply continuous_snd" here gives: invalid apply tactic, failed to unify continuous (λ (x : ↥real_gt_one × ↥real_gt_one), ↑(x.fst)) with continuous prod.snd
  apply continuous.sub,
  apply continuous_const,
  apply real.continuous.inv _ sorry,
  sorry,
end

view this post on Zulip Greg Langmead (Jan 26 2020 at 18:59):

I have an instance that indicates real_gt_one is a topological_space but somehow continous_snd is not type matching. Is it because I am using a lambda?

view this post on Zulip Joe (Jan 26 2020 at 19:03):

Looking at the error message. it seems that you should apply continuous_fst?

view this post on Zulip Joe (Jan 26 2020 at 19:07):

Also there is a coercion sign, so perhaps you can try refine continuous.comp _ _ and see what comes out.

view this post on Zulip Greg Langmead (Jan 26 2020 at 19:18):

Sorry yes continuous_fst is what I should be using, and gives me the error, and I prepared my post with _snd by mistake.

invalid apply tactic, failed to unify continuous (λ (x : ↥real_gt_one × ↥real_gt_one), ↑(x.fst)) with continuous prod.snd

I didn't succeed yet with continuous.comp, will keep trying.

view this post on Zulip Alex J. Best (Jan 26 2020 at 19:24):

lemma certain_twovar_func_continuous : continuous (λx:real_gt_one × real_gt_one, (x.1:) * (1 - (x.2:)⁻¹)) :=
begin
  apply continuous.mul _ _,
  apply_instance,
  refine continuous.comp _ _,
  apply continuous_subtype_val,
  apply continuous_fst,
  apply continuous.sub,
  apply continuous_const,
  refine real.continuous.inv _ _,
  intros,
  have := a.2.2,
  intro,
  sorry,
  refine continuous.comp _ _,
  apply continuous_subtype_val,
  apply continuous_snd,
end

now I got stuck proving that a.snd.val \ne 0

view this post on Zulip Joe (Jan 26 2020 at 19:28):

@Greg Langmead I guess you can take a look at how nnreal is defined?

view this post on Zulip Joe (Jan 26 2020 at 19:29):

#check nnreal
#check nnreal.continuous_coe

view this post on Zulip Greg Langmead (Jan 27 2020 at 14:15):

@Alex J. Best I'm stuck there too. I'm having trouble getting from being an element of real_gt_one to being > 1. All real_gt_one is is a function to Prop and I can't discover the paradigm for accessing the values for which that Prop is true.

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 14:27):

real_gt_one gets promoted to a type here, because you have terms of that type. So it's not a function to Prop when you use it (there is probably a little up-arrow next to it indicating the promotion). If x has type real_gt_one then x.2 will be a proof that x.1>1.

view this post on Zulip Alex J. Best (Jan 27 2020 at 14:29):

Yeah I ended up getting stuck with x.1 vs x.val vs \u x or some other silliness, that exact mod cast didn't want to blast through for me.

view this post on Zulip Johan Commelin (Jan 27 2020 at 14:34):

Those should all be definitionally equal...

view this post on Zulip Johan Commelin (Jan 27 2020 at 14:34):

Can you paste code?

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 14:41):

  have := a.2.2,
  { intro,
    change (a.snd : ) > 1 at this,
    linarith },

view this post on Zulip Jonathan Sejr (Jan 27 2020 at 18:54):

Hi, I am working on the natural numbers game (great stuff btw), and am currently stuck at advanced addition world l. 13. I am having trouble manipulating the expressions when my goal is false. My code so far is
python intro h, rw succ_eq_add_one at h, rw ← zero_add(n) at h, rw add_comm at h, rw ← add_comm(0) at h, rw add_assoc at h, rw zero_add(n+1) at h, rw ← add_comm(1) at h, rw one_eq_succ_zero at h,
Leaving me with n : mynat, h : 0 + n = succ 0 + n ⊢ false I want to use add_right_cancel to get 0=succ 0 and then finish off the goal. But I cannot apply add_right_cancelbecause the goal is just a false proposition.
I am really lost on how to manipulate a false goal, so any tips are appreciated.

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 18:57):

add_right_cancel is a theorem of the form "if m+p=n+p then m=n"

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 18:58):

so it's actually a function which eats a proof of m+p=n+p and spits out a proof of m=n

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 18:58):

so instead of manipulating the goal, you can make a new hypothesis

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 19:00):

have h2 := add_right_cancel _ _ _ h, would give you h2 : 0 = 1

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 19:00):

oh great and then you can use zero_ne_succ

view this post on Zulip Jonathan Sejr (Jan 27 2020 at 19:07):

I was actually trying have, but didn't get that I should tag an h at the end thanks! And now I am unsure how to finish it, h2 : 0 = 1should now be a false statement so I should be able to finish with exact h2, but that doesn't work.
Edit: One finishes off with
have h3 := zero_ne_succ _ h2, exact h3,
because h3 will be false .

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 19:57):

Remember that lots of things are functions

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 19:58):

A not= B is the same as (A=B) -> false

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 19:59):

You can probably just do exact zero_ne_succ _ h2

view this post on Zulip Kevin Buzzard (Jan 27 2020 at 19:59):

And you can probably go a step further back

view this post on Zulip Alex Kontorovich (Jan 28 2020 at 14:52):

Hi all, I'm a mathematician, completely new to Lean. Finally followed Kevin's advice and joined here (so I don't have to bug him directly for help). To get started, I want to formalize that the square of an odd number is odd. Here's what I came up with for a statement:

lemma square_of_odd_is_odd : ∀ n : ℕ, (∃ k : ℕ, n=2k+1) -> (∃ l : ℕ, nn = 2*l+1) :=
begin
intro n,
intro p,

At this point I'm stuck. How do I tell it to use that k and stick it in to n?

view this post on Zulip Kenny Lau (Jan 28 2020 at 14:52):

```lean
[some lean code]
```

view this post on Zulip Kenny Lau (Jan 28 2020 at 14:53):

you can do cases p

view this post on Zulip Alex Kontorovich (Jan 28 2020 at 14:56):

Ok great, thanks! Then

use 2*p_w^2+2*p_w,

Then how do I apply p_h?

view this post on Zulip Johan Commelin (Jan 28 2020 at 15:00):

I would suggest cases p with k p

view this post on Zulip Johan Commelin (Jan 28 2020 at 15:00):

To get nicer names

view this post on Zulip Johan Commelin (Jan 28 2020 at 15:01):

After that, you are looking for rw p_h (or rw p, if you change the cases)

view this post on Zulip Johan Commelin (Jan 28 2020 at 15:02):

Alternative: subst n. This will look for n = ... in you context, and replace all occurences of n with ...

view this post on Zulip Alex Kontorovich (Jan 28 2020 at 15:02):

Ah yes, rw! Thanks. Now shouldn't simp do the algebra for me and finish?

Let's see if this works:

lemma square_of_odd_is_odd :  n : , ( k : , n=2*k+1) -> ( l : , n*n = 2*l+1)
:=
begin
    intro n,
    intro p,
    cases p with k p,
    use 2*k^2+2*k,
    rw p,
    simp,
end

view this post on Zulip Johan Commelin (Jan 28 2020 at 15:03):

I don't think simp will do that for you. But ring should.

view this post on Zulip Alex Kontorovich (Jan 28 2020 at 15:03):

Yes! Works! Thanks that's great!

view this post on Zulip Johan Commelin (Jan 28 2020 at 15:03):

You might need import tactic at the top of your file.

view this post on Zulip Sam Stites (Jan 28 2020 at 16:31):

Super dumb question (I've never touched a theorem prover before, just going through the lean book now -- apologies in advance). I'm wondering if lean4 (or maybe even in lean3) you can construct objects via a C/C++ FFI. This was a feature that I noticed in other theorem provers, but haven't seen anywhere in the lean docs.

view this post on Zulip Johan Commelin (Jan 28 2020 at 16:32):

Lean 3, not really
Lean 4, yep, that's the plan

view this post on Zulip Sam Stites (Jan 28 2020 at 16:34):

very cool! could you give a rough idea of when we can expect lean4?

view this post on Zulip Johan Commelin (Jan 28 2020 at 16:34):

Not really... maybe end of this year. Maybe next year...

view this post on Zulip Johan Commelin (Jan 28 2020 at 16:34):

It's open source. Some parts are already usable.

view this post on Zulip Johan Commelin (Jan 28 2020 at 16:35):

But the tactic framework isn't there yet. So for maths (my field) it isn't really usable yet.

view this post on Zulip Sam Stites (Jan 28 2020 at 16:37):

that's a good enough estimate for me!

view this post on Zulip Sam Stites (Jan 28 2020 at 16:38):

Would the google groups be the best way to track progress? or perhaps the releases on github? nevermind! just going to do both. Thanks!

view this post on Zulip ROCKY KAMEN-RUBIO (Jan 29 2020 at 06:28):

Hi everyone, I'm a new Lean user and trying to work through some of the code in Kevin's lecture tutorial. I'm trying to define is_even using the inductive type like he does, but keep getting this error. Does anyone know what's causing this? Thanks! Screen-Shot-2020-01-29-at-1.26.38-AM.png

view this post on Zulip Alex J. Best (Jan 29 2020 at 06:33):

I think you are missing the bar character | at the start of each line

view this post on Zulip Alex J. Best (Jan 29 2020 at 06:33):

inductive is_even :   Prop
| zero : is_even 0
| step {n} : is_even n  is_even (n+2)

view this post on Zulip Nicholas Talin (Jan 30 2020 at 01:42):

Are there versioned tarball releases of Mathlib? I made an XBPS template for Lean itself and would like to make one for Mathlib too. It looks like the latest releases in the repo are from 2019.

view this post on Zulip Bryan Gin-ge Chen (Jan 30 2020 at 01:44):

The mathlib-nightly releases may have what you want.

view this post on Zulip Johan Commelin (Jan 30 2020 at 06:38):

@Nicholas Talin Cool! I'm also using Void. Haven't yet looked into making XBPS templates though. Thanks for doing this. It might be useful to create a template for the supporting tools cache-olean and update-mathlib. Because if you have 10 Lean projects you might want them to depend on 10 different versions of mathlib. In practice a global mathlib install isn't used very much by most people in the community.

view this post on Zulip Nicholas Talin (Jan 30 2020 at 09:23):

Since it looks like both scripts are in PyPI's mathlibtools, I guess the Lean template is all that's needed.

view this post on Zulip Nicholas Talin (Jan 30 2020 at 09:44):

Should I be using 3.4.2 instead of 3.5.0?

view this post on Zulip Johan Commelin (Jan 30 2020 at 10:00):

We are in the middle of a transition to 3.5c

view this post on Zulip Johan Commelin (Jan 30 2020 at 10:01):

@Nicholas Talin So I think you're good when you stick with that.

view this post on Zulip Mason Marche (Jan 30 2020 at 17:43):

Is there a stream for troubleshooting installation? I'm having an issue with the mathlib

view this post on Zulip Scott Morrison (Jan 30 2020 at 17:44):

Right here!

view this post on Zulip Kevin Buzzard (Jan 30 2020 at 17:46):

Are you following https://github.com/leanprover-community/mathlib#installation ?

view this post on Zulip Mason Marche (Jan 30 2020 at 17:47):

Right now I'm on macos and it looks like I've done everything correctly to install and build mathlib, but for some reason, VScode gives me the error 'Unknown Identifier Q' whenever I type \Q

view this post on Zulip Kevin Buzzard (Jan 30 2020 at 17:47):

Did you import data.rat or data.rat.basic or whatever it's called now?

view this post on Zulip Kevin Buzzard (Jan 30 2020 at 17:48):

(probably either work now)

view this post on Zulip Mason Marche (Jan 30 2020 at 17:48):

That fixed it, thanks!

view this post on Zulip Kevin Buzzard (Jan 30 2020 at 17:49):

If that worked then you're almost certainly up and running.

view this post on Zulip Mason Marche (Jan 30 2020 at 17:49):

It looks like I am

view this post on Zulip Mason Marche (Jan 31 2020 at 00:15):

Second dumb question, what's the library I need to import to access real numbers (ℝ)?

view this post on Zulip Yury G. Kudryashov (Jan 31 2020 at 00:16):

data.real.basic

view this post on Zulip Mason Marche (Jan 31 2020 at 00:16):

thank you

view this post on Zulip Chris B (Jan 31 2020 at 00:22):

Is the implementation of nat.sqrt/nat.sqrt_aux in mathlib original or is there somewhere I can read about it? I don't interact with bitwise stuff very frequently and I'm curious why it works the way it does.

view this post on Zulip Daniel Keys (Jan 31 2020 at 01:16):

Just starting chapter 4 in "Theorem proving with Lean". How does one produce an arbitrary element of type α in this example (among the exercises)?

variable α : Type
variable a : α
variable r : Prop
example : r  ( x : α, r) :=
begin
    intro pr,
    exact exists.intro _ pr
end

view this post on Zulip Jeremy Avigad (Jan 31 2020 at 01:22):

If the exercise doesn't give t to you, it is a mistake: you need something like variable a : α in the assumptions. In Lean, types can be empty.

view this post on Zulip Daniel Keys (Jan 31 2020 at 01:23):

There is a variable a : α, but how can I make use of it inside the example?

view this post on Zulip Chris B (Jan 31 2020 at 01:26):

If you have variable a : α somewhere, you need to put include <variable name> above the term if you want to use variables in tactic blocks (between the begin and end)

variable α : Type
variable r : Prop
variable a : α

include a
example : r → (∃ x : α, r) :=
begin
    intro pr,
    exact exists.intro a pr
end

view this post on Zulip Chris B (Jan 31 2020 at 01:26):

But in the snippet you only have variable α : Type.

view this post on Zulip Bryan Gin-ge Chen (Jan 31 2020 at 01:27):

You can also refer to a if you write the proof in term mode:

variables (α : Type)
variable a : α
variable r : Prop

example : r  ( x : α, r) := λ hr, exists.intro a hr

view this post on Zulip Daniel Keys (Jan 31 2020 at 01:29):

Thanks! Including a, this is what I was missing! I edited the snippet and added a to the variables.

view this post on Zulip Chris B (Jan 31 2020 at 01:31):

There's some more detail and some stuff explaining why you actually need the include/omit bits in the Lean reference manual at the bottom of p. 37.

view this post on Zulip Bryan Gin-ge Chen (Jan 31 2020 at 01:41):

There's a discussion in 6.2 of TPiL as well.

view this post on Zulip Mario Carneiro (Jan 31 2020 at 10:45):

Is the implementation of nat.sqrt/nat.sqrt_aux in mathlib original or is there somewhere I can read about it? I don't interact with bitwise stuff very frequently and I'm curious why it works the way it does.

@Chris B I think I am the one responsible for the current implementation of nat.sqrt. I am pretty sure I got it from a wikipedia article, and I think it is the "iterative algorithm" mentioned here.

view this post on Zulip Mario Carneiro (Jan 31 2020 at 10:47):

I'm not finding the description I originally worked from, the ones I can find all look different

view this post on Zulip Mario Carneiro (Jan 31 2020 at 10:50):

Aha, it is the isqrt() function given here: Methods of computing square roots

view this post on Zulip Kevin Buzzard (Jan 31 2020 at 11:30):

Aah, the old "bring digits down two at a time" method -- this is the method my father taught me for computing square roots by hand, although he used base 10.

view this post on Zulip Daniel Keys (Feb 02 2020 at 18:58):

Hi all, is there a way to write the lambda expression I'm using below in more of a tactics mode style?

variables (α : Type) (p q : α  Prop)
variable a : α
variable r : Prop

include a
theorem T10L : (( x, p x)  r)   x, p x  r :=
begin
    intros Axpx_r,
    cases ( em ( x, p x) ) with Axpx nAxpx,
    { -- case ax
        exact exists.intro a ( λ w, Axpx_r Axpx )
    },
    { sorry }
end

view this post on Zulip Kevin Buzzard (Feb 02 2020 at 19:39):

theorem T10L : (( x, p x)  r)   x, p x  r :=
begin
    intros Axpx_r,
    cases ( em ( x, p x) ) with Axpx nAxpx,
    { use a,
      intro w,
      apply Axpx_r,
      assumption
    },
    { sorry }
end

But use is a lean tactic from the maths library so you'll need import tactic at the top of your file (and mathlib).

Without mathlib you can just write existsi instead of use, but existsi doesn't work so well as an introduction rule for more complicated existential statements.

view this post on Zulip Daniel Keys (Feb 02 2020 at 19:43):

Thanks Kevin! I did see similar things in the number game, but apparently I need some more work before it sinks.

view this post on Zulip Kevin Buzzard (Feb 02 2020 at 19:43):

This software has a huge learning curve.

view this post on Zulip Kevin Buzzard (Feb 02 2020 at 19:44):

It's worth the climb though ;-)

view this post on Zulip Daniel Keys (Feb 02 2020 at 19:53):

I'm having a very good time learning it, too bad I can basically only use the weekends. The community is very helpful though!

view this post on Zulip Paul van Wamelen (Feb 05 2020 at 14:45):

Ultra noob question: Why can't I prove that x^2 = x * x over the integers?

variable x : ℤ
#reduce x + (-6)^2

example (x : ℤ) : x = x := by refl

example (x : ℤ) : x^2 = x * x := by simp

Gives simplify tactic failed to simplify. Actually with import data.int.basic the -6 doesn't even reduce. Using import data.zmod.basic reduces -6, but not (apparently) x^2. What am I missing? Any clues would be greatly appreciated!

view this post on Zulip Kevin Buzzard (Feb 05 2020 at 14:50):

import algebra.group_power

example (x : ) : x^2 = x * x := by library_search
-- exact pow_two x

view this post on Zulip Kevin Buzzard (Feb 05 2020 at 14:51):

and indeed pow_two hasn't been tagged with the simp attribute, so simp doesn't know about this lemma.

view this post on Zulip Kevin Buzzard (Feb 05 2020 at 14:55):

If you only import data.int.basic then you don't get the function aba^b with aZa\in\mathbb{Z} and bNb\in\mathbb{N}. This is because the definition of the power function is made for aa in an arbitrary monoid and bNb\in\mathbb{N}, so you have to import some group theory library to get it, not the integer library!

view this post on Zulip Paul van Wamelen (Feb 05 2020 at 15:14):

Got it! Thanks! I think I'm going to have some follow up questions though :)

view this post on Zulip Kevin Buzzard (Feb 05 2020 at 15:17):

I've been having followup questions since 2017 ;-)

view this post on Zulip Kevin Buzzard (Feb 05 2020 at 15:18):

it turns out that some stuff that mathematicians think of as "should be straightforward" is actually an interesting research project in the formal proof verification community.

view this post on Zulip Kevin Buzzard (Feb 05 2020 at 15:21):

import algebra.group_power

attribute [simp] pow_two

example (x : ) : x^2 = x * x := by simp

I am not 100% clear about why pow_two is not tagged with simp, but simp-tagging is a subtle issue best left to those who know a lot more computer science than me -- I don't really understand the algorithm. All I know is that tagging everything with simp is a bad idea.

view this post on Zulip Chris Hughes (Feb 05 2020 at 15:22):

by ring should work here, or perhaps by abel if it has been updated to deal with multiplicative monoids.

view this post on Zulip JDM (Feb 05 2020 at 16:28):

Hi people, it's been a while since I have done anything concerning Lean but I am back with renewed interest. Back when I took notice there was no real way to get it working with Windows and I didn't have a reasonble option to use Linux, but now I do. So as a complete and utter noob with building things on Linux: how do I go about this?

view this post on Zulip Patrick Massot (Feb 05 2020 at 16:28):

Don't build it.

view this post on Zulip JDM (Feb 05 2020 at 16:29):

Okay, in that case, are there detailed installation instructions?

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:29):

Yes, see github readme

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:29):

Lemme fetch the link

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:30):

https://github.com/leanprover-community/mathlib#installation

view this post on Zulip JDM (Feb 05 2020 at 16:31):

Oh, that's great, thanks a lot!

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:31):

We actually went through a transition to a new version of Lean today

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:31):

For the first time in ~ 2 years

view this post on Zulip JDM (Feb 05 2020 at 16:31):

Seems like a good time to get started then

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:31):

So let's hope the instructions still work

view this post on Zulip JDM (Feb 05 2020 at 16:31):

That's a good point :-D

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:32):

If anything goes wrong, please report here :wink:

view this post on Zulip JDM (Feb 05 2020 at 16:33):

Will do, I'm absolutely thrilled in any case :-)

view this post on Zulip Rob Lewis (Feb 05 2020 at 16:33):

For the first time in ~ 2 years

That's not really true, 3.4.2 moved some stuff from core to mathlib and that was done about a year ago. But this is the first time we're pointing to a version of Lean off the official leanprover site, and the first time with a lot of the supporting tools.

view this post on Zulip Johan Commelin (Feb 05 2020 at 16:35):

Ok, maybe I was exagerating. Your explanation is more exciting anyway :slight_smile:

view this post on Zulip Matt Earnshaw (Feb 06 2020 at 12:31):

is there a way to "unfold" what a tactic is doing in a particular case? for example I can prove x \in {x} by finish (which is how set.mem_singleton is defined), but I'm a bit curious what's going on there

view this post on Zulip Cerek Hillen (he) (W2'20) (Feb 06 2020 at 12:53):

Not sure if this is exactly what you want, but you could do #check on the theorem that includes it?

view this post on Zulip Daniel Keys (Feb 06 2020 at 14:01):

You can use #print, which gives you the whole proof. Many times that will be more than you want.

view this post on Zulip Cerek Hillen (he) (W2'20) (Feb 06 2020 at 14:05):

Sorry, mixed up my macros--meant #print haha

view this post on Zulip Daniel Keys (Feb 06 2020 at 14:09):

Is there anyone who can help me with advice on how to embed Lean code in LaTex? There are lines of code in the mathlib-paper in section 4.2 for example, but I couldn't make that look not nearly as nicely myself. Verbatim doesn't work because of the UTF characters, even with additional packages. I can hack text to look like Lean code by using \texttt and isolating math characters, but that's a lot of tedious work. If someone has a sample document.tex file with Lean code to attach (like the mathlib-paper.tex stripped down, for example) it would help a lot.

view this post on Zulip Anne Baanen (Feb 06 2020 at 14:13):

You can use the lstlean.tex file available here: https://github.com/leanprover-community/lean/tree/master/extras/latex

view this post on Zulip Daniel Keys (Feb 06 2020 at 14:18):

Works great, thank you!

view this post on Zulip Matt Earnshaw (Feb 06 2020 at 14:25):

@Daniel Keys @Cerek Hillen (he) (W2'20) perfect thanks

view this post on Zulip Kevin Buzzard (Feb 06 2020 at 15:34):

Note that the simp and tidy and library_search tactics have options where they can print out what they did. With simp you have to run squeeze_simp instead -- I think for the other two it just works automatically.

As for Lean code in LaTeX, when I tried this when I wrote my article for the LMS newsletter, some stuff came out really poorly, and when I asked @Rob Lewis he suggested that I had a super-old version of lstlean.tex and he sent me a newer one. I think the super-old version is the one which Anne has linked to. I had problems with some unicode characters IIRC.

view this post on Zulip Johan Commelin (Feb 06 2020 at 15:39):

If that is the case, we should update that link.

view this post on Zulip Rob Lewis (Feb 06 2020 at 15:39):

I'll update it to my current version in a bit.

view this post on Zulip Daniel Keys (Feb 06 2020 at 16:01):

Yes indeed, several of the Unicode characters in sample.tex seem to give me quite some trouble.

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:04):

You have to include a package for unicode characters, or else all the lean unicode characters will be garbled in tex

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:05):

I think it is \usepackage[utf8]{inputenc}

view this post on Zulip Daniel Keys (Feb 06 2020 at 16:06):

Also some symbols, like $\mathbb{C}$ are not listed, and trying to use math mode in \lstinline doesn't work.
@Mario Carneiro Yes, that package is included in the preamble.

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:06):

or possibly \usepackage[utf8x]{inputenc}

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:07):

Math mode doesn't work inside \lstinline. I think there is a way to set the escape character so this works though

view this post on Zulip Rob Lewis (Feb 06 2020 at 16:08):

The package requirements are mentioned in the md file in the directory Anne linked.

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:08):

If a symbol is not listed, you can add it to lstlean.tex. (This is why Floris, and Rob, and I, all have uncommitted modifications to lstlean.tex since the last version some 3 years ago)

view this post on Zulip Rob Lewis (Feb 06 2020 at 16:11):

https://github.com/leanprover-community/lean/pull/110

view this post on Zulip Rob Lewis (Feb 06 2020 at 16:12):

Probably a bunch more keywords could be removed, since they're mostly used in tactic mode and it's weird to highlight them there.

view this post on Zulip Daniel Keys (Feb 06 2020 at 16:38):

Since the Unicode characters are quite difficult to copy/paste and most of us are used to LaTex math symbols, it would be helpful if anyone knew how to use (escape into) math mode inside \lstinline.

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:43):

The majority of lean snippets in tex papers I get by copying from a real lean file

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:43):

which of course has much better facilities for producing unicode

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:45):

There is a mathescape= option in lstlean.tex that you can set to true if you want $foo$ to enter math mode. This interferes with lean's use of $, though, so it's usually turned off

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:45):

I think you can also set these options directly in your preamble

view this post on Zulip Mario Carneiro (Feb 06 2020 at 16:48):

You can of course always write everything in tex if you want to do that, i.e. $\mathtt{\color{blue}{inductive} foo (\alpha : Type) : Type}$

view this post on Zulip Daniel Keys (Feb 08 2020 at 22:11):

Anyone can show me how to construct a finset ℤ from range n, where n : ℕ and every member is the negative of one of the elements in the range? Some kind of mapping should be possible.

view this post on Zulip Patrick Massot (Feb 08 2020 at 22:26):

finset.image (λ m : ℕ, -(m : ℤ)) (finset.range n)

view this post on Zulip Patrick Massot (Feb 08 2020 at 22:27):

I have no idea why finset.map is not what you were looking for.

view this post on Zulip Chris Hughes (Feb 08 2020 at 22:29):

Also finset.Ico_ℤ

view this post on Zulip Daniel Keys (Feb 08 2020 at 22:32):

Thanks @Patrick Massot @Chris Hughes
I don't know how to use finset.map yet. For example, I tried to get the same entries (not the negatives) with finset.map int.of_nat (range 5), but that doesn't work. The symbol used in finset.lean for the mapping function is new to me at this point (the "curved" arrow).

view this post on Zulip Chris Hughes (Feb 08 2020 at 22:35):

You can do it with map like this

example (n : ) : finset  := finset.map int.of_nat, @int.of_nat.inj
  (finset.range n)

map only works with injective functions, the curly arrow is an embedding, a pair of a function, and a proof that it's injective.

map is faster for computation since it doesn't erase duplicates.

view this post on Zulip Patrick Massot (Feb 08 2020 at 22:37):

Why isn't called fast_map or inj_map then? It would leave the canonical name for the canonical operation.

view this post on Zulip Patrick Massot (Feb 08 2020 at 22:38):

Daniel, you can use "jump to definition" in VScode also on symbols.

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 16:49):

How do I get the proofs for simple things like n + n = 2 * n or 1 < 2? How do I prove 1 < 2? I was expecting these proofs would already be in the library and not hiding from the user

view this post on Zulip Patrick Massot (Feb 09 2020 at 16:50):

ring and norm_num would do these for you.

view this post on Zulip Patrick Massot (Feb 09 2020 at 16:50):

Assuming you use mathlib.

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 16:54):

in chapter 8... haven't been introduced to these yet

view this post on Zulip Patrick Massot (Feb 09 2020 at 16:55):

You need to give us more context then. Are you doing a specific exercise in TPIL?

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 16:56):

In 8.4, the second last example. trying to solve the sorry

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 16:57):

nat_to_bin

view this post on Zulip Patrick Massot (Feb 09 2020 at 16:59):

I don't think this is meant as an exercise. I think Jeremy didn't want to distract readers with details of this proof.

view this post on Zulip Daniel Keys (Feb 09 2020 at 17:00):

@Sayantan Majumdar Here is a slightly more complex proof. Something like you want is part of it, see the have h1:

theorem sumUpToN_1 (n : ) : 2 * (range (n + 1)).sum id = n * (n + 1) :=
begin
  induction n with d hd,
  refl,
  rw sum_range_succ,
  rw mul_add,
  rw hd,
  rw id.def,
  rw nat.succ_eq_add_one,
  ---------- can get the goal thus
  rw add_assoc d 1 1,
  rw  nat.succ_eq_add_one 1,
  rw  add_mul 2 d (d+1),
  have h1 : nat.succ 1 = 2, from rfl,
  rw h1,
  rw add_comm 2 d,
  rw mul_comm (d+2) (d+1),
  ------------ or simply by:
  -- ring,
end

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:02):

Daniel -- instead of rewriting h1, which is true by definition, you can use the change tactic to just rewrite the goal to what you want it to be

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 17:03):

I understand the h1, 1 < 2 seems far too complicated to prove. It would be easier to shift to Coq

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:03):

Again, norm_num proves it. What else do you want?

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:04):

How can a proof be simpler than a single tactic invocation?

view this post on Zulip Daniel Keys (Feb 09 2020 at 17:05):

@Patrick Massot Yes, Patrick, but we beginners need to learn the basics of expressing ourselves in Lean.

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 17:05):

So, how do I prove it with norm_num?

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:06):

example : 1 < 2 := by norm_num

view this post on Zulip Daniel Keys (Feb 09 2020 at 17:06):

@Sayantan Majumdar Here is a proof for your initial quest:

variable n : 
theorem twoEqOneOne : 2 * n = n + n :=
begin
  have h1 : 2 = nat.succ 1, from rfl,
  rw h1,
  rw nat.succ_eq_add_one 1,
  rw add_mul,
  rw one_mul, done
end

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 17:07):

thanks. How did you find the succ_eq_add_one? is there a good way of searching for these?

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:09):

Here is another proof:

variable n : 
theorem twoEqOneOne : 2 * n = n + n :=
begin
  show (1 + 1) * n = n + n,
  rw add_mul,
  rw one_mul
end

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:09):

import tactic

example (n : ) : 2*n = n + n :=
begin
  ring,
end

example (n : ) : 2*n = n + n :=
begin
  library_search,
end

view this post on Zulip Daniel Keys (Feb 09 2020 at 17:09):

I had all those problems you have before going through the natural number game. Kevin Buzzard did a great job with that! It can get you started.

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:10):

Again, either you want to suffer because you think this is a good exercise, and then I don't understand what you are complaining about. Or you can use the answers I provided one minute after you asked.

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:11):

@Sayantan Majumdar certain lemmas you just end up learning because they come up a lot. You can use library_search to find them.

import tactic

variable n : 

open nat

theorem what_is_this_called : succ n = n + 1 :=
begin
  library_search -- we learn it is true by definition
end

view this post on Zulip Daniel Keys (Feb 09 2020 at 17:11):

@Kevin Buzzard Kevin, does change need import tactic?

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:12):

show certainly doesn't. I prefer change because it works on hypotheses as well as goals so it's easier for the beginner.

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:13):

@Sayantan Majumdar there is also a naming convention which we stick to in Lean, meaning that most users can after a while guess that succ n = n + 1 will be called succ_eq_add_one. But it takes a while to learn the conventions.

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 17:14):

Thanks @Kevin Buzzard @Daniel Keys was looking for a better way to find all the proofs available. I was using the naming convention and using print and relying on vscode intelligence

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:15):

I have no reason to believe that this is any harder in Lean than in Coq or any other theorem prover. There will be naming conventions, and tactics for people who don't know the names but want to get the job done.

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:16):

The best way to get information about this sort of thing is to ask here. The existence of this chat room is one thing which makes learning Lean easier than learning all the other systems -- for the other systems you have to ask on a mailing list or stackoverflow.

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:17):

He asked, by then decided to ignore the answer and start writing he should use Coq.

view this post on Zulip Daniel Keys (Feb 09 2020 at 17:18):

Here's a chat newbie question, how do you get a reply box to look reddish instead of white?

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:18):

Mention some name using @

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:18):

That person will see a reddish box

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 17:18):

@Patrick Massot I have to use theorems that I have already proved to proof this, I can't use rings and norm_num because I haven't reached there yet

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:19):

Again, I think you misunderstood the status of this theorem. It's not an exercise. And if you want to make it an exercise, then why shouldn't you learn how to search properly?

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:20):

1 < 2 can also be proven by dec_trivial

view this post on Zulip Daniel Keys (Feb 09 2020 at 17:22):

@Sayantan Majumdar Have a look at this, it involves an inequality:

https://stackoverflow.com/questions/59669492/how-to-switch-types-in-lean-theorem-prover-when-constants-are-involved#comment105499922_59669492

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:22):

library_search would have solved both your goals.

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:23):

If you are working from the absolute basics, 1 < 2 is nat.le_refl 2, where nat.le_refl is proven by induction

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:27):

But I think Patrick is right -- I don't think there is enough in TPIL for the learner working through the book to easily remove that sorry. It is trivial to remove using the machinery that mathlib provides but because TPIL is about Lean not mathlib, Jeremy leaves it there. If you're trying to remove it then you're moving away from the carefully chosen basic examples in TPIL and the real world of actual mathematical formalisation. mathlib has solved all your problems in lots of different ways but you have to learn mathlb like you have to learn Lean.

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:28):

two_mul has a proof using commutativity to turn it inro n*2 which is defeq to 0+n+n

example (n : ) : 2 * n = n + n :=
eq.trans (mul_comm 2 n) $
congr_arg (λ i, i + n) $ zero_add _

But this is a really low level proof. Just use the theorems, or better yet, the general tactics to kill this goal.

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:29):

For the record, the full sorry can be replaced by by rw nat.div_lt_iff_lt_mul ; linarith,

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:29):

@Sayantan Majumdar Mario's proof probably works without mathlib :-)

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:30):

(after being disappointed by omega :sad:)

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:30):

omega doesn't do it??

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:30):

omega doesn't like me. It never does what I ask it to do.

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:31):

This works for me:

example (n : ) : 2 * n = n + n := by omega

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:31):

it's because you were too rude about nat subtraction a year ago

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:31):

This is not the full thing, Mario.

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:31):

Patrick is proving (n+2)/2<n+2

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:31):

that's the sorry in TPIL

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:31):

aha

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:32):

example (n : ) : (n+2)/2<n+2 :=
nat.div_lt_self dec_trivial dec_trivial

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:33):

this is the problem when people know the libraries too well ;-)

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:33):

example (n : ) : (n+2)/2<n+2 :=
by rw nat.div_lt_iff_lt_mul; omega

view this post on Zulip Mario Carneiro (Feb 09 2020 at 17:34):

I'm not sure what omega's status is wrt integer division

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:34):

so omega just hates Patrick personally

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:34):

No, I meant by omega alone.

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:35):

No rewriting first.

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 17:35):

So I guess division is beyond the capabilities of omega is the concluson

view this post on Zulip Rob Lewis (Feb 09 2020 at 17:36):

FYI, https://github.com/leanprover-community/mathlib/issues/1484#issuecomment-561260385

view this post on Zulip Rob Lewis (Feb 09 2020 at 17:36):

Although #1748 definitely needs to be finished first.

view this post on Zulip Patrick Massot (Feb 09 2020 at 17:43):

Thanks Rob!

view this post on Zulip Paul van Wamelen (Feb 09 2020 at 19:11):

Oh! I figured out what TPIL stands for :). Can I suggest a small improvement to TPIL? (see, I can even use it in a sentence):
In exercise 1 at the end of chapter 3, as one of the many "other properties", the reader is asked to prove ¬(p ↔ ¬p), but then this is also broken out as exercise 3. As exercise 2 is all about classical the assumption is that exercise 1 should be without it. Exercise 3 is certainly interesting enough that breaking it out seems justified. I would suggest removing it from exercise 1.

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 19:14):

¬(p ↔ ¬p) can be proved without LEM, but it's tricky.

view this post on Zulip Paul van Wamelen (Feb 09 2020 at 19:50):

Right, and exercise 3 asks the reader to do it without LEM. But even in exercise 1 the assumption/implication is that they should be done without LEM. I'm just saying the duplication should probably be removed. I was stuck on exercise 1 for a long time until I noticed that I was essentially already working on exercise 3. By the time I was through with exercise 2, I could (finally) work through 3.

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 21:49):

Anyone have an idea how to solve this e I have

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 21:49):


view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 21:50):

example (n  : \N) ( h : 1 * (n + 2) < 2 * (n + 2)) : (n + 2) < 2 * (n + 2)

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 21:59):

I was wondering if someone could help me out with this simple proof

example (n  : \N) ( h : 1 * (n + 2) < 2 * (n + 2)) : (n + 2) < 2 * (n + 2)

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 22:17):

you can rewrite one_mul at h. After a while you'll be able to guess that one_mul is the name of the theorem which says 1*x=x.

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 22:26):

the rewrite will only work will = not <

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 22:26):

*with = not <

view this post on Zulip Reid Barton (Feb 09 2020 at 22:36):

Don't rewrite using h, rewrite h itself: rw one_mul at h

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 22:43):

thanks

view this post on Zulip Sayantan Majumdar (Feb 09 2020 at 23:04):

Anybody got any suggestions for this

example (n : ) (h₁ : 2 > 0) (h₂ : (n + 2) < ((n + 2) * 2)) : (n + 2) / 2 < (n + 2)

was thinking about using div_lt_of_mul_lt_of_pos but there seems to be an issue

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 23:06):

example (n : ) (h₁ : 2 > 0) (h₂ : (n + 2) < ((n + 2) * 2)) : (n + 2) / 2 < (n + 2) :=
begin
  rw nat.div_lt_iff_lt_mul _ _ h₁,
  exact h₂
end

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 23:07):

#check @div_lt_of_mul_lt_of_pos
/-
div_lt_of_mul_lt_of_pos :
  ∀ {α : Type u_1} [_inst_1 : linear_ordered_field α] {a b c : α}, c > 0 → b < a * c → b / c < a
  -/

div_lt_of_mul_lt_of_pos is a theorem about linearly ordered fields.

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 23:08):

example (n : ) (h₁ : 2 > 0) (h₂ : (n + 2) < ((n + 2) * 2)) : (n + 2) / 2 < (n + 2) :=
(nat.div_lt_iff_lt_mul _ _ h₁).2 h₂

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 23:09):

example (n : ) (h₁ : 2 > 0) (h₂ : (n + 2) < ((n + 2) * 2)) : (n + 2) / 2 < (n + 2) :=
begin
  rw nat.div_lt_iff_lt_mul,
  { assumption},
  { assumption}
end

view this post on Zulip Kevin Buzzard (Feb 09 2020 at 23:21):

example (n : ) (h₁ : 2 > 0) (h₂ : (n + 2) < ((n + 2) * 2)) : (n + 2) / 2 < (n + 2) :=
by rwa nat.div_lt_iff_lt_mul _ _ h₁

view this post on Zulip Matt Earnshaw (Feb 11 2020 at 13:38):

I have a function producing Props a bit like the following (but in general there can be any finite number of disjuncts)

def g (p q r s : ℕ) : Prop := (p = q) ∨ (r = s) ∨ false

now I suppose these should be decidable and hence printable, which is my aim. I have read a bit about decidable props but can't quite figure out how to reduce an application of g to a true or false

view this post on Zulip Rob Lewis (Feb 11 2020 at 13:43):

Depending on the exact structure of your function, Lean can probably infer that it's decidable already. You need either @[reducible] def g or @[derive decidable] def g (the latter will only work with mathlib). Then you can #eval to_bool (g 1 2 3 4).

view this post on Zulip Matt Earnshaw (Feb 11 2020 at 14:14):

@Rob Lewis thanks. actually my Prop was set membership, so I had to stipulate finset but then this works. at some point I will need to understand better what is going on with this "attribute" business but for now...

view this post on Zulip Rob Lewis (Feb 11 2020 at 14:23):

By default, Lean won't unfold the definition of g to see if it's decidable, because this gets very expensive. @[reducible] says "go ahead and unfold this anyway," and @[derive decidable] says "unfold this temporarily to check that it's decidable, and add an instance to the environment."

view this post on Zulip Matt Earnshaw (Feb 12 2020 at 14:44):

is there an isomorphism Type x Type with Type? I have two endofunctors on Type and it would seem nice to be able to see their product as again being (via isomorphism) another such endofunctor. perhaps this is nonsense

view this post on Zulip Yury G. Kudryashov (Feb 12 2020 at 14:48):

You clearly have Type × Type → Type. How do you want to construct Type → Type × Type?

view this post on Zulip Yury G. Kudryashov (Feb 12 2020 at 14:48):

Disclaimer: I'm not an expert in category theory.

view this post on Zulip Matt Earnshaw (Feb 12 2020 at 14:56):

well, it can just be the diagonal, but if we say def f : Type ⥤ (Type × Type) := λx, x × x, it does not typecheck

view this post on Zulip Anne Baanen (Feb 12 2020 at 15:02):

So I understand the question better: what is the inverse of (ℕ, ℝ) supposed to be under f?

view this post on Zulip Yury G. Kudryashov (Feb 12 2020 at 15:09):

A functor is more than a map.

view this post on Zulip Yury G. Kudryashov (Feb 12 2020 at 15:09):

You need at least {obj := ..., map := ...} if I remember field names correctly.

view this post on Zulip Yury G. Kudryashov (Feb 12 2020 at 15:11):

You can define functors diag : Type ⥤ (Type × Type) and prod : (Type × Type) ⥤ Type. What relations on these functors do you want?

view this post on Zulip Matt Earnshaw (Feb 12 2020 at 15:18):

yes, excuse me. I mean, I think clearly this does not work in the naive sense. So let me rephrase, why should N x N : Type? I think you can say something like type formation applies to types of a particular universe and not on that universe itself. But this typechecking example seems to indicate that we shoil be able to view any product of types as itself a Type. Am I hopelessly confused?

view this post on Zulip Anne Baanen (Feb 12 2020 at 15:23):

You can view (×) as a function prod : Type → Type → Type, Thus, ℕ : Type implies prod ℕ ℕ : Type, just like mul : ℕ → ℕ → ℕ implies that mul 1 2 : ℕ. Does that help?

view this post on Zulip Matt Earnshaw (Feb 12 2020 at 15:35):

thanks. I'm not sure now how this "thought" got off the ground at all, will press on

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 16:31):

is there an isomorphism Type x Type with Type? I have two endofunctors on Type and it would seem nice to be able to see their product as again being (via isomorphism) another such endofunctor. perhaps this is nonsense

To do that you don't need an identification of Type x Type with Type -- you just compose the endofunctors, right?

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 16:31):

There will be functor.comp or something like that.

view this post on Zulip Matt Earnshaw (Feb 12 2020 at 23:15):

There will be functor.comp or something like that.

I really needed their categorial product, not comp, but I have realized now that my mistake is that I want their product in the functor category Fun(Type, Type) (which is "calculated pointwise"), not their product in the category Type (which is what functor.prod gives, essentially)...

In defense of the idea that we might identify Type with Type × Type, it is the difference between whether there are only (types of) things in the world or if pairs (of types) of things are distinct, and not themselves (types of) things. In other words, I was thinking that if Type is sort of like a "universe of sets", and we thought that "everything is a set" then a pair of sets should itself be a set. Again, naively this doesn't work but I thought there might be some kind of "universe trick" or the like... something like the following (although this fails):

variable f : Type u  Type u
variable g : Type w  Type w

#check functor.prod f g
 -- functor.prod f g : Type u × Type w ⥤ Type u × Type w

def dummy (fg : Type (max (w+1) (u+1))  Type (max (w+1) (u+1))) := 0

#check dummy (functor.prod f g)  -- fails

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:17):

It's just not true that Type = Type x Type -- does this help?

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:17):

This equality says that given a set there is some nice way to get two sets from it.

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:18):

You can certainly bundle together two types to get a new type, but there's no natural inverse map from Type to Type x Type because most types are not two other types bundled together.

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:19):

BTW if you write ```lean instead of just ``` at the top of your quoted code then you get syntax highlighting :-)

view this post on Zulip Matt Earnshaw (Feb 12 2020 at 23:20):

no argument there

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:21):

In other words, I was thinking that if Type is sort of like a "universe of sets", and we thought that "everything is a set" then a pair of sets should itself be a set.

This part is fine -- that's going from Type x Type to Type.

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:22):

This is called sum in Lean, with notation (in VS Code it's \oplus)

view this post on Zulip Chris Hughes (Feb 12 2020 at 23:24):

I'm not sure it's fine in the sense that it was meant, there's some natural functions Type x Type to Type, but I can't just give Lean a pair of types when it expects a Type.

view this post on Zulip Chris Hughes (Feb 12 2020 at 23:26):

sums of Types are not pairs of Types.

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:26):

Oh of course you're right.

view this post on Zulip Kevin Buzzard (Feb 12 2020 at 23:31):

so it's hard to get dummy to typecheck because given a pair of types I can manufacture a type, but I can't go the other way, so I can't construct a functor Type -> Type from a functor Type^2 -> Type^2

view this post on Zulip Chris Hughes (Feb 12 2020 at 23:40):

And even though in ZFC, a pair of sets is a set, this is a useless construction categorically, since it's always just a set with two elements I think.

view this post on Zulip Daniel Keys (Feb 16 2020 at 15:33):

Is there a simple way to obtain the truth value of a Prop? Here is what I mean: when doing #reduce tt && (0=0), output is tt. Obviously Lean evaluates the truth value of (0=0) : Prop and produces a bool. But if one tries #reduce 0 = 0, the output is not a bool. I can evaluate the Prop by something like def is_tt : bool := 0 = 0 and then #reduce is_tt, but there should be a more straightforward way that Lean itself appears to use and I couldn't find.

view this post on Zulip Kevin Buzzard (Feb 16 2020 at 15:34):

There is to_bool. Is this what you're after?

view this post on Zulip Daniel Keys (Feb 16 2020 at 15:39):

That is it! Somehow I couldn't find it, although I did find something like to_bool_true_eq_tt which didn't immediately help. Thanks!

view this post on Zulip Kevin Buzzard (Feb 16 2020 at 15:59):

Don't expect to learn your way around immediately. It took me years. Tools are getting better for you to solve many problems on your own nowadays, but sometimes asking is more effective.

view this post on Zulip PolyB (Feb 17 2020 at 17:29):

I've written:

inductive type_with (v : Type → Type)
| mk (α : Type) : v α → α → with_

def f : list (type_with has_to_string) → string := ....

Is there a way to write something equivalent without having to use a "helper" type ?
If it's not possible, does type_with already exists in lean standard library/mathlib ?

view this post on Zulip Yury G. Kudryashov (Feb 17 2020 at 18:27):

If you write lean after opening a code block, then you get syntax highlighting. Are you looking for Σ α : Type, has_to_string α?

view this post on Zulip Andrew Ashworth (Feb 17 2020 at 18:30):

you might want to look at https://github.com/leanprover/lean/blob/ceacfa7445953cbc8860ddabc55407430a9ca5c3/library/init/data/rbmap/basic.lean line 60

view this post on Zulip Andrew Ashworth (Feb 17 2020 at 18:31):

that line defines a string representation for a red-black tree

view this post on Zulip PolyB (Feb 17 2020 at 18:45):

Thanks for the responses,
sigma looks almost equivalent to my type_with , but it looks like I loose instance inference

view this post on Zulip Reid Barton (Feb 17 2020 at 19:20):

I'm not sure what instance inference you have with type_with...?

view this post on Zulip Gabriel Ruiz (Feb 17 2020 at 19:33):

Hi everyone! I'm beginning my journey in Lean, and I'm following along the tutorial here:
https://leanprover.github.io/theorem_proving_in_lean/dependent_type_theory.html

Why is it that when you input #check Type to lean's interpreter(?), you're returned Type 1 instead of Type 0?

view this post on Zulip Reid Barton (Feb 17 2020 at 19:37):

Type 0 is the same as Type. If we had Type : Type, then the system would be logically inconsistent (you could encode Cantor's paradox or something).

view this post on Zulip Reid Barton (Feb 17 2020 at 19:38):

Type 1 is a "bigger universe" which can contain things like Type = Type 0, and Type 1 is itself a type that lives in the next larger universe Type 2, and so on

view this post on Zulip Yury G. Kudryashov (Feb 17 2020 at 19:46):

@Andrew Ashworth You can write def bundle_to_string (α : Type) [h : has_to_string α] : Σ α : Type, has_to_string α := ⟨α, h⟩ (didn't test).

view this post on Zulip Reid Barton (Feb 17 2020 at 19:49):

Reid Barton said:

Type 1 is a "bigger universe" which can contain things like Type = Type 0, and Type 1 is itself a type that lives in the next larger universe Type 2, and so on

I realize now I pretty much explained just the same thing it already says in https://leanprover.github.io/theorem_proving_in_lean/dependent_type_theory.html#types-as-objects

view this post on Zulip Gabriel Ruiz (Feb 17 2020 at 19:50):

@Reid Barton I'm following, and now I'm starting to see my confusion. What then does #check do?

view this post on Zulip Reid Barton (Feb 17 2020 at 19:51):

#check tells you the type of something

view this post on Zulip Reid Barton (Feb 17 2020 at 19:51):

e.g. #check 3 will print something like 3 : nat

view this post on Zulip Gabriel Ruiz (Feb 17 2020 at 19:54):

Right, which is why I'm perplexed that it doesn't actually return Type 0 when I put in #check Type 0. I understand that it's also of Type 1, but why does it tell me that instead of its actual type: Type 0?

view this post on Zulip Johan Commelin (Feb 17 2020 at 19:54):

Because that is not its type

view this post on Zulip Johan Commelin (Feb 17 2020 at 19:55):

You can't be your own type

view this post on Zulip Gabriel Ruiz (Feb 17 2020 at 19:55):

Ohhhhhhhhhhhhhhhh

view this post on Zulip Gabriel Ruiz (Feb 17 2020 at 19:55):

That clicked, thank you!

view this post on Zulip Johan Commelin (Feb 17 2020 at 19:56):

Similarly, Type 1 will have type Type 2, and Type 2 will have type ...

view this post on Zulip Paul van Wamelen (Feb 17 2020 at 20:25):

How would one do:

lemma lol : (real.sqrt 3 : ) = 2 * real.sqrt 3 / 2 :=
begin
  sorry
end

by ring manages in , should I use some coe is injective?

view this post on Zulip Floris van Doorn (Feb 17 2020 at 21:21):

The tactic norm_cast will help you with anything coe-related:

import data.complex.basic

lemma lol : (real.sqrt 3 : ) = 2 * real.sqrt 3 / 2 :=
begin
  norm_cast, ring
end

view this post on Zulip Paul van Wamelen (Feb 17 2020 at 21:58):

Thanks!
I thought maybe the real.sqrt 3 was confusing things, so I tried to prove

lemma lol' (x : ) : x = 2 * x / 2

first. I finally got this

lemma lol' (x : ) : x = 2 * x / 2 :=
begin
   rw mul_comm,
  rw div_eq_mul_inv,
  rw mul_assoc,
  rw @complex.mul_inv_cancel (2 : ),
  rw mul_one,
  intro h,
  norm_cast at h
end

(I was trying exact absurd h dec_trivial, which wasn't working, where there is now a norm_cast, thanks again! :)).
Is it really this hard? Why doesn't dec_trivial work here (it worked in very similar circumstances before)

view this post on Zulip Kevin Buzzard (Feb 17 2020 at 22:03):

dec_trivial won't prove anything about the complexes, because the complexes don't have decidable equality.

view this post on Zulip Kevin Buzzard (Feb 17 2020 at 22:04):

dec_trivial works for naturals, integers and rationals, not for reals, complexes or pp-adics.

view this post on Zulip Kevin Buzzard (Feb 17 2020 at 22:10):

import data.complex.basic

lemma lol' (x : ) : x = 2 * x / 2 :=
begin
  field_simp,
  ring,
end

view this post on Zulip Paul van Wamelen (Feb 17 2020 at 22:11):

field_simp!!!!!!

view this post on Zulip Kevin Buzzard (Feb 17 2020 at 22:13):

ring doesn't always work when you have denominators, for obvious reasons. field_simp is, I think, some kind of denominator tactic. It's the first time I ever used it; I remembered people talking about it a month or two ago and I just looked it up in the tactic list.

view this post on Zulip Paul van Wamelen (Feb 17 2020 at 22:14):

Thanks for the dec_trivial explanation. I had h : 2 = 0 but couldn't figure out in which ring 2 and 0 were. Is there a #print setting that will show me?

view this post on Zulip Kevin Buzzard (Feb 17 2020 at 22:14):

You can set_option pp.all true before your proof. Then you'll see what Lean is actually doing behind the scenes. Be warned though, it's not a pretty sight sometimes.

view this post on Zulip Paul van Wamelen (Feb 17 2020 at 22:15):

:) Thanks!

view this post on Zulip Kevin Buzzard (Feb 17 2020 at 22:16):

Maybe you could try set_option pp.numerals false instead but I'm not sure what will happen then.

view this post on Zulip Rob Lewis (Feb 17 2020 at 22:19):

lemma lol' (x : ℂ) : x = 2 * x / 2

This should be provable by ring alone -- notice it works if you change C to R. IIRC there's something in the C++ norm_num that looks for an order instance unnecessarily when it does denominator cancellation. Probably fixable in 3.5c.

view this post on Zulip Matt Earnshaw (Feb 18 2020 at 00:14):

I am defining a type of automata (DFA). Initially I had something like:

structure DFA :=
 (Alphabet : Type) (State : Type)  (initialState : Q)  (AcceptingStates : finset Q) (δ : State  Alphabet  State)

this works ok for a while, I can define some enumerated type for an alphabet and so on. but then for some applications, it would be really useful to be able to map δ over all of the letters of the alphabet. So it has to be a list,

variable {β : Type}
structure DFA :=
 (Alphabet : list β) (State : Type) (initialState : Q)  (AcceptingStates : finset Q) (δ : State  Alphabet  State)

but of course now we have bad syntax at δ because Alphabet has become a term. I can change it to δ : forall a \in Alphabet, State → State), say, but then it seems like I have to provide proofs of membership all the time. Of course there is the basic solution δ : Q → list β → Q, but this is not a very expressive type since we do not want any old list β. Is there another possibility I've missed?

view this post on Zulip Matt Earnshaw (Feb 18 2020 at 00:29):

the other possibility is my original structure is good and my desire to map is a hangover from other languages. Actually, maybe I can use rec on my alphabets qua enumerated types instead... will see if that can give the intended effect tomorrow.

view this post on Zulip Chris B (Feb 18 2020 at 01:40):

@Matt E There's a thing called fintype in mathlib that might be what you want for the alphabet, or at least be a good jumping off point. It's sort of secretly a list (the hierarchy for its definition is fintype -> finset -> multiset -> quotient of list A over list permutation). It looks like there are functions fintype.to_finset and then finset.map, or you might be able to use coercions to get what you want. For the membership stuff I would assume there are helpful lemmas in those modules. Someone more knowledgeable can probably give details.

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 10:13):

IIRC there's something in the C++ norm_num that looks for an order instance unnecessarily when it does denominator cancellation.

The point being that the order instance guarantees injectivity of any ring hom from int, rat or real, so is a cheap way of checking nonzero denominators

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 10:17):

it would be really useful to be able to map δ over all of the letters of the alphabet. So it has to be a list

Lean has all sorts of maps, as well as things like set.image. What exactly do you need? Lists are lists and if you feel like your mental model isn't a list then maybe you need something else.

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 10:17):

Maybe it's as simple as using set.range?

view this post on Zulip Matt Earnshaw (Feb 18 2020 at 14:17):

@Chris B that is indeed probably what I want. so I can put structure DFA (α : Type) [fintype α] := ... so far so good. now let

@[derive decidable_eq]
inductive α | A | B | C

now I need an instance of fintype, but I'm stuck at:

instance α_fin : fintype α := begin
  refine {elems := {α.A, α.B, α.C}, complete := _},
  intro,
  sorry
end

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 14:20):

instance α_fin : fintype α := begin
  refine {elems := {α.A, α.B, α.C}, complete := _},
  intro,
  cases x; simp,
end

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 14:21):

cases is your friend here. Given x : α where α is any inductive type, cases will split into a case for each constructor.

view this post on Zulip Matt Earnshaw (Feb 18 2020 at 14:22):

Kevin Buzzard said:

Maybe it's as simple as using set.range?

that might work once I have this fintype stuff working, the real block is having something that is finite, decidable etc.

view this post on Zulip Matt Earnshaw (Feb 18 2020 at 14:22):

Kevin Buzzard said:

cases is your friend here. Given x : α where α is any inductive type, cases will split into a case for each constructor.

perfect, thanks!

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 14:23):

Using tactic mode to define data is something I instinctively avoid doing. It is probably not an issue here, but my instinct would be instance α_fin : fintype α := {elems := {α.A, α.B, α.C}, complete := λ x, by cases x; simp}.

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 14:24):

The logic is that some tactics make terrifying terms which mean that it becomes hard to reason about the objects you've defined. I strongly suspect that refine is not one of them, but I am never sure. I do know that rw can really make things scary.

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 14:25):

that might work once I have this fintype stuff working, the real block is having something that is finite, decidable etc.

Is your alphabet finite and decidable? You can just add these as assumptions of course.

view this post on Zulip Matt Earnshaw (Feb 18 2020 at 15:19):

Kevin Buzzard said:

Is your alphabet finite and decidable? You can just add these as assumptions of course.

not exactly sure what you mean

view this post on Zulip Matt Earnshaw (Feb 18 2020 at 15:20):

that sounds like it would suffice to prove some things abstractly, but I am working with particular alphabets

view this post on Zulip Kevin Buzzard (Feb 18 2020 at 16:10):

I just meant (Alphabet : Type) [decidable_eq Alphabet] [fintype Alphabet]

view this post on Zulip Matt Earnshaw (Feb 19 2020 at 12:32):

if I have a quotient on type X and a myset : set X, is there a way to turn the latter into a set X/~? Is quotient.lift myset ... on the right track?

view this post on Zulip Sebastien Gouezel (Feb 19 2020 at 12:58):

You want to take the image of a set under a function. This is done with the notation '', which is a shortcut for set.image.

view this post on Zulip Chris B (Feb 21 2020 at 23:04):

Is there a simple-ish answer for what Lean does internally with attributes? Also are there any community docs on how to define attributes? That part of the reference manual is blank. There's a one-liner in mathlib's commands.md doc that shows the literal syntax for defining a local attribute but that's about it.

view this post on Zulip Kevin Buzzard (Feb 22 2020 at 00:45):

There aren't that many attributes. A simp tag means "simp can use this", I think refl_lemna means dsimp can use it, ext means ext can use it, to_additive means that lean will try and generate an additive version of this multiplicative definition, there are some casty ones to do with norm_cast tactic and these are explained in the tactics doc, and I think that's most of the ones I know about

view this post on Zulip Kevin Buzzard (Feb 22 2020 at 00:47):

refl andsymm and transmean that the associated tactic can use them and they can also be used in calc proofs

view this post on Zulip Mario Carneiro (Feb 22 2020 at 00:48):

You can list all the attributes, there are a lot you don't know about

view this post on Zulip Mario Carneiro (Feb 22 2020 at 00:49):

#print attributes

view this post on Zulip Kevin Buzzard (Feb 22 2020 at 00:50):

Are most of them not for human consumption though? It's not as if I see these all over mathlib

view this post on Zulip Mario Carneiro (Feb 22 2020 at 00:51):

I'm sure they are zipf distributed

view this post on Zulip Bryan Gin-ge Chen (Feb 22 2020 at 01:30):

@Rob Lewis 's doc PR will put all documentation for custom attributes into a new file. The header for that file is still WIP in the corresponding doc-gen PR here, and that would be a good spot to add info about how attributes work.

view this post on Zulip Chris B (Feb 23 2020 at 03:00):

I meant more like "what does Lean do internally when it encounters an attribute" as opposed to what a particular attribute does, but looking closer at how they're defined in mathlib's tactics module it looks like it's pretty involved meta stuff, so I think therein lies my answer.

view this post on Zulip Kevin Buzzard (Feb 23 2020 at 08:09):

Attributes are just ways of tagging a definition and simp is written in C++ so in some cases it can be C++ code not Lean code which is using those tags

view this post on Zulip Rocky Kamen-Rubio (Feb 24 2020 at 04:17):

I keep getting these errors when I try to define a matrix. I have mathlib installed and working and already did import data.matrix.basic and import data.matrix.pequiv. I feel like I'm missing something obvious Screen-Shot-2020-02-23-at-11.14.34-PM.png Screen-Shot-2020-02-23-at-11.14.24-PM.png

def m : matrix (fin 2) (fin 2)  := {{1,2},{3,4}}

view this post on Zulip Alex J. Best (Feb 24 2020 at 04:22):

Did you copy this from https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Notation.20for.20matrices.20and.20vectors ? I don't think this way of defining matrices is standard at all.

view this post on Zulip Scott Morrison (Feb 24 2020 at 04:53):

(I'd recommend not using screenshots: it's worth your effort, and everyone's here, to prepare minimum working examples of the problems you're having. Generally, at least half the time while I'm trying to prepare an example to post here for help, the process of minimising makes me realise what I'm doing wrong.)

view this post on Zulip Kevin Buzzard (Feb 24 2020 at 07:23):

Yeah, screenshots are much harder to view on mobile. Post code!

view this post on Zulip Rocky Kamen-Rubio (Feb 24 2020 at 18:01):

Scott Morrison said:

(I'd recommend not using screenshots: it's worth your effort, and everyone's here, to prepare minimum working examples of the problems you're having. Generally, at least half the time while I'm trying to prepare an example to post here for help, the process of minimising makes me realise what I'm doing wrong.)

I'll keep that in mind going forward. I did post the code below the screenshot as well, but maybe got hidden because it was only one line. I do think I've relied maybe a little too heavily on screenshots here so I will be more conscientious of that. Thank you!

Alex J. Best said:

Did you copy this from https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Notation.20for.20matrices.20and.20vectors ? I don't think this way of defining matrices is standard at all.

I did! Looking back at that post I'm realizing that initially I thought that notation was standard and the post was about defining new notation for other operations. I got it to work using functions, but am still wondering if there's a better way to define a matrix with arbitrary values than defining a function like this

--Lambda definition. This seems ok if there's a functional relationship between the values x and y and the element at position (x,y)
def m : matrix (fin 5) (fin 5)  := λ x : (fin 5), (λ y : (fin 5), (10*x + y))

--inconvenient function definition. I know I could condense this down to a single lambda statement, but it still doesn't seem great if I have a list of values I want to turn into a matrix. Is this a necessary consequence of functional programming? I'm not seeing a more convenient "constructor " in mathlib/src/data/matrix

def r1 (y : (fin 3)) :  :=
  if (y = 1) then 1 else
  if (y = 2) then 2 else
  3

def r2 (y : (fin 3)):  :=
  if (y = 1) then 4 else
  if (y = 2) then 5 else
  6

def r3 (y : (fin 3)):  :=
  if (y = 1) then 7 else
  if (y = 2) then 8 else
  9

def c (x : (fin 3)) : (fin 3)   :=
if x = 1 then r1 else
if x = 2 then r2 else
r3

def myMatrix : matrix (fin 3) (fin 3)  := c

--EDIT: somewhat better way of representing a matrix but this still doesn't seem great.
def myMatrix2 : matrix (fin 3) (fin 3)  := λ (x y : fin 3),
if x = 1 then
  if y = 1 then 1 else
  if y = 2 then 2 else
  3
else if x = 2 then
  if y = 1 then 4 else
  if y = 2 then 5 else
  6
else
  if y = 1 then 7 else
  if y = 2 then 8 else
  9

view this post on Zulip Bryan Gin-ge Chen (Feb 24 2020 at 18:16):

Do you know about pattern-matching syntax?

def r1 : fin 3  
| 1, _⟩ := 1
| 2, _⟩ := 2
| _ := 3

view this post on Zulip Alex J. Best (Feb 24 2020 at 18:42):

You could define a little helper function like this:

import data.list.defs

variables {α : Type} [inhabited α]

def list_of_list_to_mat {n : } : list (list α)  (matrix (fin n) (fin n) α) :=
λ ll x y, (ll.inth (x)).inth (y)

#eval (list_of_list_to_mat [[1,2],[0,2]] : matrix (fin 2) (fin 2) )  1 0

view this post on Zulip Rocky Kamen-Rubio (Feb 24 2020 at 20:29):

Cool! This seems useful. Thank you!

view this post on Zulip Ethan Horsfall (Feb 29 2020 at 16:07):

for the logic and proof tutorial, when i run the code in visual studios it sometimes doesn't run and instead just says 'updating' indefinitely. This has happened on a few examples. The current one is
variables A B : Prop

example : A ∧ ¬ B → ¬ B ∧ A :=
assume h : A ∧ ¬ B,
show ¬ B ∧ A, from and.intro (and.right h) (and.left h)

While on my RHS under 'Lean messages' it says 'Updating'

view this post on Zulip Johan Commelin (Feb 29 2020 at 16:12):

Pro tip:

```lean
code like this gets highlighted
```

view this post on Zulip Johan Commelin (Feb 29 2020 at 16:12):

Concerning your question: how have you installed Lean?

view this post on Zulip Ethan Horsfall (Feb 29 2020 at 16:44):

I followed the instructions from 'logical verification in lean' and then enabled the extension in VS studios. When doing that one of the steps I think didn't work (or, I messed it up, which is probably the case as I have never used vs studios before). Some of the code is running however. I can always use the online browser tool for the moment

view this post on Zulip Kevin Buzzard (Feb 29 2020 at 16:58):

NB it's supposed to say "updating" indefinitely. This just means "if you press a button, I'll update"

view this post on Zulip Patrick Massot (Feb 29 2020 at 17:00):

We really really need to rephrase that "Updating". Every newbie gets confused by this message.

view this post on Zulip Kevin Buzzard (Feb 29 2020 at 17:03):

How about "ready"?

view this post on Zulip Bryan Gin-ge Chen (Feb 29 2020 at 17:56):

Maybe "Active" or "Live" makes more sense since Lean may or may not be busy processing stuff?

The intention of that button is to be able to pause / unpause the updating of the info view. This is useful if you're making changes to a slow proof and you want to keep the info view from refreshing over and over while you refer to something in the context.

view this post on Zulip Patrick Massot (Feb 29 2020 at 19:15):

Maybe the clearest thing would be to name the button rather than describing state. For instance "Freeze display"/"Unfreeze display"

view this post on Zulip Kevin Buzzard (Feb 29 2020 at 19:27):

The issue is not when expert users are editing a slow proof, the issue is when beginners think that Lean has hung because (a) it doesn't seem to be doing anything [because everything is working] and (b) it says "updating" in the top right [which makes it sound a lot like Lean is doing something]. This can happen in particular if a user has managed to click on the "display messages" button rather than the "display goal" button -- if all is well then "display messages" can be empty, so Lean just "sits there updating".

If we're in the business of changing stuff like this, can we also change the "Lean Messages" title of the "Display Goal" view to "Lean Goal"?

view this post on Zulip Bryan Gin-ge Chen (Feb 29 2020 at 19:33):

I agree completely. I'll make a PR later with some changes.

view this post on Zulip Bryan Gin-ge Chen (Feb 29 2020 at 19:54):

Would it actually even be better if we just removed the text next to the button altogether? The button already has a tooltip assigned to it that says "Stop updating" / "Continue updating", which I can change to "Freeze display" / "Unfreeze display".

view this post on Zulip Kevin Buzzard (Feb 29 2020 at 20:55):

Kids these days all speak some universal language of symbols, and that pause button symbol is certainly one of the standard symbols in this language, as is the green triangle which appears when you click it.

view this post on Zulip Patrick Massot (Feb 29 2020 at 20:55):

Yes, maybe removing the words would be enough.

view this post on Zulip Bryan Gin-ge Chen (Feb 29 2020 at 21:06):

:+1:

PR: https://github.com/leanprover/vscode-lean/pull/145

view this post on Zulip Reid Barton (Feb 29 2020 at 22:35):

you don't press ctrl-S to freeze the info window, and ctrl-Q to unfreeze it?

view this post on Zulip Reid Barton (Feb 29 2020 at 22:35):

Kids these days

view this post on Zulip Bryan Gin-ge Chen (Feb 29 2020 at 22:39):

Haha, you could bind both ctrl+S and ctrl+Q to lean.infoView.toggleUpdating for that old-school feel if you really wanted.

view this post on Zulip Bobby Lindsey (Mar 02 2020 at 03:21):

Hey guys, hoping I can contribute to this project. But having a hard time figuring out where (other than "issues" list in GitHub). E.g. this page of list of theorems that have been proved lead to 404 errors: https://github.com/leanprover-community/mathlib/blob/master/docs/theories.md. Recommendations for good places to start?

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 03:24):

Which area of mathematics do you prefer?

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 03:24):

There are plenty of holes in any area.

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 03:26):

By "holes" I mean "not yet formalized definitions/theorems".

view this post on Zulip Bobby Lindsey (Mar 02 2020 at 03:26):

Probability, stats, or linear algebra. But not sure if all undergrad theorems/lemma have been implemented already... I only have a M.S. in math. I'd be happy to attempt to contribute elsewhere though if need be

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 03:32):

We have some linear algebra and measure theory. There should be quite a few holes in our linear algebra library but I notice them only when I need them, so let's wait for someone who has better understanding of the current state of src/linear_algebra.

view this post on Zulip Mario Carneiro (Mar 02 2020 at 03:35):

Not sure what's up with the broken links. @Reid Barton you were the last one to touch this file, where have the functions.md et al files gone?

view this post on Zulip Reid Barton (Mar 02 2020 at 03:36):

The topology one isn't broken :upside_down:

view this post on Zulip Bobby Lindsey (Mar 02 2020 at 03:36):

Other than cross referencing linear algebra theorems/lemmas with those mentioned in textbooks, is there any better way to enumerate these holes? Better yet, an index of what has been proven would go a long way... perhaps this documentation is something I can help out with as well

view this post on Zulip Mario Carneiro (Mar 02 2020 at 03:37):

The enumeration of holes is difficult because the set of holes in mathlib is cofinite

view this post on Zulip Mario Carneiro (Mar 02 2020 at 03:40):

As for what has been proven, there are of course the source files themselves, which take some getting used to but are not an unreasonable way to familiarize yourself with the contents. But the mathlib docs are a less intimidating view on the source files

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 03:42):

If you see a theorem that has a name, then adding a docstring with this name is definitely worth a PR.

view this post on Zulip Bobby Lindsey (Mar 02 2020 at 03:48):

Thanks @Mario Carneiro , I'll check those docs out. And thanks @Yury G. Kudryashov for the suggestion. I'll start combing through the linear_algebra module and cross-referencing its contents with theorems/lemmas in some textbooks I have, and try to fill in any documentation and missing theorems/lemmas along the way. Thanks guys :)

view this post on Zulip Sam Stites (Mar 02 2020 at 16:59):

I'm trying to say the following lemma: Let A be a ring with the following properties: for all rings R, there exists a unique homomorphism A → R. Then A ≅ ℤ.

I have a few attempts, but could someone help me formulate this? My first attempt looks like the following (It's basically how I would do this in haskell):

import algebra.ring
import logic.unique

variables (A : ring Type) (R : ring Type)
lemma lemma03_v0 : A → (∀ R → unique (A → R)) → (A ≅ ℤ) := sorry

Things that I think are wrong: \forall should be \exists and maybe there should only be one → before A ≅ ℤ? I still get a lot of unexpected tokens or invalid expressions, though.

view this post on Zulip Anne Baanen (Mar 02 2020 at 17:01):

To say "A is a ring", you can write variables (A : Type*) [ring A]. In Haskell terms, [ring A] can be interpreted as the typeclass constraint (Ring A) => ...

view this post on Zulip Anne Baanen (Mar 02 2020 at 17:03):

The next error is ∀ R → ...: the should be a , (something that I still mess up continually, coming from Agda)

view this post on Zulip Reid Barton (Mar 02 2020 at 17:07):

This kind of thing is easier using the bundled/category theory approach

import algebra.category.CommRing

variables (A : Ring.{0})
lemma lemma03_v0 : (Π (R : Ring.{0}), unique (A  R))  (A  Ring.of ) :=
sorry

view this post on Zulip Reid Barton (Mar 02 2020 at 17:17):

otherwise, I think it's

variables (A : Type) [ring A]
lemma lemma03_v0 : (Π (R : Type) [ring R], by exactI unique (ring_hom A R))  (A +* ) :=
sorry

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:18):

Why would you use the Pi notation instead of forall here? I know they are the same to Lean, I'm asking about psychology

view this post on Zulip Reid Barton (Mar 02 2020 at 17:19):

Well, unique is data. Really it should be def too, and not lemma

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:20):

Oh. I would have never suspected unique to be data.

view this post on Zulip Johan Commelin (Mar 02 2020 at 17:20):

Yeah, I should have called it cunique...

view this post on Zulip Johan Commelin (Mar 02 2020 at 17:21):

But now you have a chance to PR discrete_unique. Doesn't that make you feel happy?

view this post on Zulip Sam Stites (Mar 02 2020 at 17:23):

cool! thanks for all of this -- I'm running into some weird compilation stuff right now (probably need to clean up this experiment-repo).

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:24):

The version without category stuff doesn't read nice, but I guess this is fair: the lemma is really category theoretic in flavor.

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:24):

Sam, do you understand what exactI is doing?

view this post on Zulip Sam Stites (Mar 02 2020 at 17:27):

not at the moment (I was going to wait for matlib to rebuild before examining in depth). I am also wondering what the longer arrow is in your unique (A --> R) is.

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:27):

Why are you rebuilding mathlib?

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:28):

Reid's longer arrow is Hom in the category library.

view this post on Zulip Sam Stites (Mar 02 2020 at 17:28):

Oh! it's a tactic? I was about to start reading that chapter next.

view this post on Zulip Sam Stites (Mar 02 2020 at 17:28):

cool

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:28):

Yes, exactI is a tactic, and not the easiest one to understand.

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:28):

But first we need to make sure you don't need to rebuild mathlib. Why do you think you need to do that?

view this post on Zulip Sam Stites (Mar 02 2020 at 17:31):

ehh... it's a little silly -- I am using emacs for the first time (normally I use vim) and flycheck seems to be maxing out on errors. I think it's a caching issue since I was trying to use some certigrad files.

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:31):

Lean is already difficult, don't add emacs difficulty on top of it if you are not a emacs user.

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:32):

Why don't you use VScode?

view this post on Zulip Sam Stites (Mar 02 2020 at 17:32):

ah, it's working out fine, actually! that's not my main concern : )

view this post on Zulip Sam Stites (Mar 02 2020 at 17:33):

Yeah, so I've cleaned up the repo and rebuilt with leanpkg build -- the flycheck seems to be working perfectly fine now

view this post on Zulip Sam Stites (Mar 02 2020 at 17:34):

I'm at the point in my programming career where it's quite painful not to use vim and emacs has good support for this via spacemacs. It's self-inflicted pain, no need to worry about it!

view this post on Zulip Johan Commelin (Mar 02 2020 at 17:34):

VScode has a vim plugin

view this post on Zulip Johan Commelin (Mar 02 2020 at 17:34):

Both Patrick and I use it.

view this post on Zulip Johan Commelin (Mar 02 2020 at 17:35):

It doesn't have all the goodies of regular vim, but it's quite close.

view this post on Zulip Sam Stites (Mar 02 2020 at 17:35):

okay! I'll check it out as well

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:36):

I still strongly advise you to use VScode. But let's go back to exactI because I have very little time before leaving my office (Paris time-zone). So the issue is ring_hom A R expects to find a (semi)-ring structure on A and R by type class search. The one on A will be found without problem, because it's there from the beginning. The one on R is mentioned too late in the game to be picked up if you don't ask Lean to search. That's what exactI is doing (asking Lean).

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:37):

If you want to avoid that exactI you'll need to tell Lean to forget about how this semi-ring structure was meant to be found, and provide it yourself. This would be:

lemma lemma03_v0' :
( (R : Type) ( hR : ring R), ∃! φ : @ring_hom A R _ hR.to_semiring, true)  (A +* ) :=
sorry

which also has a silly way of saying there exists a unique φ with type @ring_hom A R _ hR.to_semiring.

view this post on Zulip Patrick Massot (Mar 02 2020 at 17:38):

Now I need to go. Have fun!

view this post on Zulip Sam Stites (Mar 02 2020 at 17:38):

thank you!

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:10):

If you move the universal hypothesis before the colon, you don't need all this exactI stuff:

import data.equiv.algebra

variables (A : Type) [ring A]

lemma lemma03_v0' (huniv :  (R : Type) [ring R], ∃! φ : ring_hom A R, true) : (A +* ) :=
sorry

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:29):

import data.equiv.algebra

variables (A : Type) [ring A]

noncomputable lemma lemma03_v0' (huniv :  (R : Type) [ring R], ∃! φ : ring_hom A R, true) : (A +* ) :=
{ to_fun := (classical.some (huniv )).to_fun,
  inv_fun := λ n, sorry, -- what's the map from ℤ to an arbitrary ring?
  left_inv := sorry,
  right_inv := sorry,
  map_mul' := (classical.some (huniv )).map_mul,
  map_add' := (classical.some (huniv )).map_add }

Once I figure out the name of the canonical map from the integers to an arbitrary ring, I think we're nearly done (the ring hom A -> A must be the identity by uniqueness).

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:31):

Oh -- I hadn't seen the unique trick, that makes it cleaner.

view this post on Zulip Reid Barton (Mar 02 2020 at 18:31):

I hadn't realized the "left of the colon" would work that way in this context, thanks.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:32):

Funnily enough, I realised this myself just the other day when I was trying to formalise the assertion that if X×YYX\times Y\to Y was always closed then XX was compact.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:33):

Another thing I noticed was that if I restricted to YY in the same universe as XX then the result was actually stronger not weaker -- universe monomorphism FTW. The same is going on in here (possibly unintentionally)

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:34):

import data.equiv.algebra

variables (A : Type) [ring A]

lemma lemma03_v0' (huniv :  (R : Type) [ring R], unique (ring_hom A R)) : (A +* ) :=
{ to_fun := (huniv ).default.to_fun,
  inv_fun := λ n, sorry, -- what's the map from ℤ to an arbitrary ring?
  left_inv := sorry,
  right_inv := sorry,
  map_mul' := (huniv ).default.map_mul,
  map_add' := (huniv ).default.map_add }

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:34):

I don't think that it's stronger because you can't say "for all Y from all universes"

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:35):

Yes but this is an input, not an output, so if I know it for all Y in all universes, I can deduce it for all Y in the same universe as X, which is all I need.

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:35):

So, if you use (X : Type u) (Y : Type v), then it says "if for all Y from some universe v (possibly not u), then ..."

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:37):

Yes.

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:37):

And this does not immediately imply "for all Y : Type u"

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:37):

Yes.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:38):

But u might equal v

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:38):

so in this case, I win (and I agree that usually I lose)

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:38):

So, the result with (X : Type u) (Y : Type v) is stronger.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:38):

No

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:39):

because I am demanding more from my input and only getting the same for my output

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:40):

The point is exactly that this is not def f (X : Type u) (Y : Type v) ...

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:41):

I'm saying "assume that something is true for all Y in the same universe as X. Then P(X)", which is a better thing to do than saying "assume that something is true for all Y in all universes, including X's and others. Then P(X)"

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:41):

Try this:

universes v u
constant P : Type u  Type v  Prop
axiom L1 (X : Type u) (Y : Type v) : P X Y
lemma L2 (X Y : Type u) : P X Y := L1 X Y

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:42):

Your examples are not a good mirror of what is going on here.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:42):

Read the statement of the lemma.

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:43):

OK, which lemma are we talking about?

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:43):

lemma lemma03_v0' (A : Type) [ring A] (huniv : ∀ (R : Type) [ring R], unique (ring_hom A R)) : (A ≃+* ℤ) := ...

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:44):

If I let R : Type u then huniv is harder to verify, but the result is still the same.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:45):

So it seems to be a weird case where less polymorphism is better. I noticed this last week when I was proving that if X×YYX\times Y\to Y is closed for all YY then XX is compact.

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:45):

Ah, it should be

universes v u
constant p : Type u  Type v  Prop
constant q : Type u  Prop
axiom L1 (X : Type u) (H :  Y : Type v, p X Y) : q X
lemma L2 (X : Type u) (H :  Y : Type u, p X Y) : q X := L1 X H

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:46):

I was trying to prove this for all YY in all universes, and then I ran into some issue with universes, so then I thought "crap I am going to have to restrict to YY in the same universe as XX" and then I thought "oh wait, that's a stronger result!"

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:47):

wait -- so you're still saying I'm wrong? :-/

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 18:53):

Actually L1 is not one axiom but a series of axioms enumerated by v and u.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:56):

I completely see that your code compiles. However what is wrong with the argument that says the following: I have X and I want to prove q X. Now X is in a universe u. Would I rather prove H X Y for all Y in all universes v, or would I rather prove H X Y in the easier case that Y is in universe u as well? Clearly I would rather stick to Y in universe u, so L2 is a more useful lemma than L1 because it applies more widely.

view this post on Zulip Reid Barton (Mar 02 2020 at 18:57):

Kevin you're comparing L2 with a hypothetical L2' that can't be expressed in Lean, but would look something like (X : Type u) (H : forall v (Y : Type v), p X Y) -> q X

view this post on Zulip Reid Barton (Mar 02 2020 at 18:58):

And you're correct that L2 is stronger than L2'

view this post on Zulip Johan Commelin (Mar 02 2020 at 18:58):

Apparently in Lean it's not forall v but exists v

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 18:58):

L1?

view this post on Zulip Reid Barton (Mar 02 2020 at 18:58):

Yury's L1 becomes L2 when you specialize it to v = u

view this post on Zulip Johan Commelin (Mar 02 2020 at 18:58):

Unless you require v = u

view this post on Zulip Reid Barton (Mar 02 2020 at 18:59):

Probably L1 is false in this setting if you allow v < u. You would only be able to show compactness for v-sized filters, roughly

view this post on Zulip Reid Barton (Mar 02 2020 at 19:00):

The other thing going on here is that in the implication in the other direction, you can state it for all v (because now v is at the outer level) and it is true.

view this post on Zulip Reid Barton (Mar 02 2020 at 19:01):

So for X : Top.{u}, you have "X is u-universally closed" => "X is compact" => "for any v, X is v-universally closed"

view this post on Zulip Reid Barton (Mar 02 2020 at 19:01):

and in that sense you've proved a stronger statement than you expected

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 19:06):

No wonder I was having trouble proving it in the fully polymorphic setting! I wanted to let Y be this option X with a filter topology.

view this post on Zulip Reid Barton (Mar 02 2020 at 19:08):

To take a slightly silly extreme case, it's clearly not true if you only allow Y to range over Prop/subsingletons

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 19:09):

That was surprisingly interesting/insightful. So back to the original question -- if we make the construction fully universe polymorphic then it seems to me that things get a bit more tedious because I have to start using ulift to get the map from Z\mathbb{Z} to A

view this post on Zulip Reid Barton (Mar 02 2020 at 19:12):

Yeah, I stuck to Type 0 in order to avoid this ulift stuff. In the "category theory" version it will appear already in the statement, but even in the unbundled version it will appear in the proof.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 19:31):

import data.equiv.algebra algebra.group_power

variables (A : Type) [ring A]

open_locale add_group -- breakthrough

lemma lemma03_v0' (huniv :  (R : Type) [ring R], unique (ring_hom A R)) : (A +* ) :=
{ to_fun := (huniv ).default.to_fun,
  inv_fun := λ n, n  1,
  left_inv := sorry,
  right_inv := sorry,
  map_mul' := (huniv ).default.map_mul,
  map_add' := (huniv ).default.map_add }

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 19:39):

Is this not a thing in mathlib?

def of_int (A : Type*) [ring A] :  →+* A :=
{ to_fun := λ n, n  1,
  map_one' := by simp,
  map_mul' := λ x y, show (x * y)  (1 : A)= x  1 * (y  1), by simp [gsmul_eq_mul],
  map_zero' := zero_gsmul _,
  map_add' := λ _ _, add_gsmul _ _ _ }

view this post on Zulip Mario Carneiro (Mar 02 2020 at 21:17):

That's int.cast

view this post on Zulip Mario Carneiro (Mar 02 2020 at 21:17):

not sure if it's been bundled yet

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 21:18):

Thanks. I was pretty sure I'd seen it before.

view this post on Zulip Mario Carneiro (Mar 02 2020 at 21:18):

also known as the coercion from int to a ring

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 22:00):

import data.equiv.algebra algebra.group_power

variables (A : Type) [ring A]

def of_int :  →+* A := ring_hom.of coe

theorem eq_of_int (φ :  →+* ) (a : ) : φ a = a := @int.induction_on' (λ x, φ x = x) a 0
   φ.map_zero (λ k _ hk, by rw [φ.map_add, hk, φ.map_one]) (λ k _ hk, by rw [φ.map_sub, hk, φ.map_one])

lemma eq_int_of_unique_hom (huniv :  (R : Type) [ring R], unique (ring_hom A R)) : (A +* ) :=
{ to_fun := (huniv ).default,
  inv_fun := of_int A,
  left_inv := begin
    intro x,
    show _ = (ring_hom.id A) x,
    have h1 := (huniv A).uniq (ring_hom.id A),
    have h2 := (huniv A).uniq ((of_int A).comp (huniv ).default),
    rw h1 at h2,
    rw h2,
    refl,
  end,
  right_inv := λ n, eq_of_int ((huniv ).default.comp (of_int A)) n,
  map_mul' := (huniv ).default.map_mul,
  map_add' := (huniv ).default.map_add }

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 22:05):

I hadn't found the coercion earlier because I didn't have the right import. Kind of annoying that I don't know how to say "hey Lean, I want a coercion from int to a ring, go find me one in mathlib". All I knew was that when I tried it, it didn't work.

view this post on Zulip Kevin Buzzard (Mar 02 2020 at 22:06):

I thought data.equiv.algebra would give me everything ringy, but it was in data.int.basic. I guess this just shows that I don't understand the import tree well enough. I would have guessed integers were more fundamental than ring stuff (probably because I learnt them earlier in my mathematical education)

view this post on Zulip Bobby Lindsey (Mar 02 2020 at 23:48):

How are we using Kolmogorov axioms for probability theorems? For example, what would lean code look like for P(empty set) = 0. Do we have to appeal to measury theory instead? Sorry, still trying to find my way around this project... but I'm trying to write all probability and stats theorems/lemmas in an undergrad textbook with lean.

view this post on Zulip Yury G. Kudryashov (Mar 02 2020 at 23:50):

As far as I understand, we don't plan to have a separate probability theory. Just deal with a measure space of total measure one.

view this post on Zulip Bobby Lindsey (Mar 02 2020 at 23:52):

Would anyone think it'd be useful? I know I would have loved to have something like this while going through probability theory as a student - if anything just to exercise proof-solving skills. But many students who take probability theory don't go on to take measure theory (unless they're math majors).

view this post on Zulip Bryan Gin-ge Chen (Mar 03 2020 at 00:00):

We're not currently suffering from an overabundance of expository Lean files (to say the least), so yes, I think it'd be very useful!

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 00:03):

@Bryan Gin-ge Chen :) any suggestions for where to put it in the mathlib project? Like maybe src/probability_theory? Or should expository stuff go somewhere else

view this post on Zulip Scott Morrison (Mar 03 2020 at 00:04):

Well... it's not exactly clear what place there is for purely "expository" stuff at all.

view this post on Zulip Scott Morrison (Mar 03 2020 at 00:05):

We do have the docs/tutorial/ folder, which I think is a great place to show people how to do "standard" / "undergraduate" stuff using the highbrow API that Lean tends to provide.

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 00:10):

@Scott Morrison Cool, thanks for the suggestion. Now to figure out how to create all these axioms and whatnot...

view this post on Zulip Bryan Gin-ge Chen (Mar 03 2020 at 00:15):

It really depends what you end up formalizing. Stuff that will be useful for future developments shouldn't (only) be in docs/tutorial and should go in something like src/probability_theory. I wouldn't worry about it too much now though.

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 00:50):

Sooo.. I might be out of my depth here. I'm trying to figure out how to define a sample space to start building Kolmogorov axioms but have no idea how to fit this into LEAN's type theory. I'm afraid I've bit off more than I can chew :( How did you experts bootstrap this learning curve?

view this post on Zulip Mario Carneiro (Mar 03 2020 at 00:56):

I think it might help to focus your question a bit more. What did you try and how did you get stuck?

view this post on Zulip Mario Carneiro (Mar 03 2020 at 00:58):

Regarding probability theory, I think we have some things about measure_space and possibly probability_space if @Koundinya Vajjha PR'd his stuff

view this post on Zulip Mario Carneiro (Mar 03 2020 at 01:00):

If you look at the definition of outer_measure, measure and measure_space you will get an idea how we do things like P(empty set) = 0. (hint: we write P ∅ = 0)

view this post on Zulip Scott Morrison (Mar 03 2020 at 02:03):

You might also tell us your background: have you tried formalising anything simpler yet? Have you played the natural numbers game, and/or read some of Theorem Proving in Lean?

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 02:24):

Haven't formalized anything simple yet - currently working through the natural numbers game. Love it so far. I'm probably getting ahead of myself though which is why looking at formalizing Kolmogorov axioms seems so daunted to me atm :/.

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 14:27):

How would I go about defining a probability space in LEAN? This would be some probability triple but what data type would a sample space belong to? I started trying to define the first axioms like def prob_event_nonnegative (E: set ℝ) := { x : ℝ | x ≥ 0} and def prob_sample_space_is_one (Ω: ??) := but I soon realized I don't have a probability space defined. Not sure if I'm on the right track or not, just trying to get to a point where I can start writing prob 101 theorems and solving them

view this post on Zulip Johan Commelin (Mar 03 2020 at 14:41):

I'm not a probability theorist, so I don't know the maths definitions. Is a probability space just a measure space such that the measure of the total space is 1?

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 14:49):

Yeah, that's right. I'd like to define it separately so as to assume no knowledge of measure theory though, but having a hard time as to how it should be typed.

view this post on Zulip Reid Barton (Mar 03 2020 at 14:53):

Do you know about structures in general?

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 15:00):

I do not. Just found it in the docs though :)

view this post on Zulip Reid Barton (Mar 03 2020 at 15:01):

If the definitions of measure space and probability space have 90% overlap, then someone interested in probability spaces cannot really have no knowledge of measure theory

view this post on Zulip Reid Barton (Mar 03 2020 at 15:03):

quite aside from the practical advantages of reusing the existing formalization (no reinvention of wheels, near-duplication of proofs, etc)

view this post on Zulip Reid Barton (Mar 03 2020 at 15:08):

Of course if your goal is to reinvent wheels and reformalize proofs for learning purposes, that's another matter

view this post on Zulip Bobby Lindsey (Mar 03 2020 at 15:13):

It's mostly for learning purposes. I'm taking the viewpoint of a student who takes probability theory, like an engineer, but does not go on to taking measure theory.

view this post on Zulip Reid Barton (Mar 03 2020 at 15:33):

There is "measure theory" and then there is the definition of a measure space. A student who missed the lecture on the axiom "the probability of the whole space is 1" knows the definition of a measure space. (Okay, maybe not quite since a measure can also take the value ++\infty.)

view this post on Zulip Arjun Pitchanathan (Mar 03 2020 at 15:50):

Maybe it would be interesting to formalize the proofs of the Markov and Chebyshev inequalities. As far as I can tell they don't exist in mathlib already.

view this post on Zulip Koundinya Vajjha (Mar 04 2020 at 02:47):

I have the Markov+Chebyshev inequalities proven in another repository. I really should PR them. Feel free to build off of these, in any case.

https://github.com/jtristan/stump-learnable/blob/21358ffd6746d838f76b6d1a275d361d5ea66125/src/lib/attributed/to_mathlib.lean#L154

view this post on Zulip Daniel Keys (Mar 12 2020 at 21:37):

Here's a stripped-down version of some proofs I need:

def X : set  := { n | n^2 < 10 }

lemma Xexplicit : {0, 1, 2, 3}  X :=
begin
  dsimp,
  have h1 : 1 ^2 < 10, norm_num,
  sorry,
end

While it's trivial to prove all the elements in the enumerated set satisfy the condition for X-membership, as shown for 1, how does one put things like these together to obtain the result? Do I need to revert to something simpler, like n ∈ X \iff n = 0 \or n = 1 \or ...? In that case things can get a little ugly for larger sets.

view this post on Zulip Kevin Buzzard (Mar 12 2020 at 21:39):

I'm not sure this is true, because I think means but not =

view this post on Zulip Kevin Buzzard (Mar 12 2020 at 21:43):

import tactic

def X : set  := { n | n^2 < 10 }

lemma Xexplicit : {0, 1, 2, 3}  X :=
begin
  simp [X, set.subset_def],
  intros x hx,
  repeat {cases hx}; exact dec_trivial
end

view this post on Zulip Daniel Keys (Mar 12 2020 at 21:43):

Actually I need that to prove equality, so I need inclusion both sides.

view this post on Zulip Daniel Keys (Mar 12 2020 at 21:43):

I edited to have \subseteq.

view this post on Zulip Daniel Keys (Mar 12 2020 at 21:44):

Thank you!

view this post on Zulip Kevin Buzzard (Mar 12 2020 at 21:45):

Confession: @Chris Hughes suggested the first line, but then wanted to finish with finish and we couldn't get it to work, hence the hack

view this post on Zulip Daniel Keys (Mar 12 2020 at 21:46):

Anyway much shorter than what I was contemplating.

view this post on Zulip Yury G. Kudryashov (Mar 13 2020 at 00:04):

BTW, what do you think about using subsetneq instead of subset?

view this post on Zulip Yury G. Kudryashov (Mar 13 2020 at 00:06):

This will make statements more readable

view this post on Zulip Kevin Buzzard (Mar 13 2020 at 00:12):

I never use (\ssub) in my work or my lectures, because it is one of these ambiguous symbols used by some people to mean one thing, and used by others to mean something else. But then again I never use \nat either, for the same reason. The counter-argument is that if mathlib decides to stick to a convention and advertises that in some sort of "notation" page, this would perhaps suffice. I don't think →ₗ, etc are particularly readable either (but this is a little different because perhaps there is no standard notation for them?)

view this post on Zulip Mario Carneiro (Mar 13 2020 at 02:34):

I think you can do better than that:

lemma Xexplicit : {0, 1, 2, 3}  X :=
by simp [X, set.insert_subset]; exact dec_trivial

view this post on Zulip Mario Carneiro (Mar 13 2020 at 02:35):

insert_subset should just be a simp lemma, I don't think there are any downsides to triggering it

view this post on Zulip Daniel Keys (Mar 14 2020 at 20:41):

Trying some basic analysis stuff on my own:

def unbounded_above (A : set ) :=  x : , x > 0   a  A, x < a

then I want to prove, among others, unbounded_above ℕ. So I need to coerce the whole of nat as set of real. Can that be done?

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:42):

I guess it would be something like coe '' nat and you'll need import data.set.basic

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:42):

wait that's not quite right

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:43):

set.range (coe : nat -> real)

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:44):

Why not just ∀ x : ℝ, ∃ a ∈ A, x < a?

view this post on Zulip Daniel Keys (Mar 14 2020 at 20:52):

Yeap, this works:

lemma nats_unbounded_above : unbounded_above ( set.range (coe :  -> ) ) := sorry

Thank you! Agreed, I could get rid of the x>0 here; trying to show equivalence with a version of the Archimedes principle where that will be helpful though (keep 1/x in the nats instead of ints).

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:53):

You could also use {x : ℝ | ∃ n : ℕ, x = n}

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:54):

the equality is between two terms of different types. Lean reads the left hand side first and decides this is an equality between reals, and then coerces the natural automatically

view this post on Zulip Daniel Keys (Mar 14 2020 at 20:54):

Oh wait! That's exactly the same thing, right?

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:55):

{x : ℝ | ∃ n : ℕ, x = ↑n} also works. They're the same sets in the sense that they have the same elements, and they might well be defeq

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:55):

oh apparently they're not :-/

view this post on Zulip Kevin Buzzard (Mar 14 2020 at 20:57):

the range is defeq to {x : ℝ | ∃ n : ℕ, (n : ℝ) = x}

view this post on Zulip Daniel Keys (Mar 15 2020 at 01:10):

Can someone help me at this stage?

import data.real.basic
def unboundedAbove (A : set ) :=  x : , x > 0   a  A, x < a
def archimPrinciple :=  x : , x > 0    n : , (1/n : ) < x
lemma nats_unboundedAbove :
    unboundedAbove {x :  |  n : , x = n}  archimPrinciple :=
begin
    split,
    intros unb x hx,
    set A := {x :  |  n : , x = n} with hA,
    have h1x : (1/x) > 0, from one_div_pos_of_pos hx,
    have h1 := unb (1/x) h1x,
    cases h1 with nx hnx,
    cases hnx with h1 h2,
    -- existsi nx,  -- this won't work because nx is real, although it should be nat as well
    -- but I don't know how to get that from h1
end

view this post on Zulip Chris Hughes (Mar 15 2020 at 01:42):

You can use ceil nx to find the next natural number after nx

view this post on Zulip Mario Carneiro (Mar 15 2020 at 01:45):

I think that trivializes the statement though

view this post on Zulip Bryan Gin-ge Chen (Mar 15 2020 at 01:45):

I think you want something like this?

import data.real.basic
def unboundedAbove (A : set ) : Prop :=  x : , x > 0   a  A, x < a
def archimPrinciple : Prop :=  x : , x > 0    n : , (1/n : ) < x
lemma nats_unboundedAbove :
  unboundedAbove {x :  |  n : , x = n}  archimPrinciple :=
begin
  split,
  { intros unb x hx,
    set A := {x :  |  n : , x = n} with hA,
    have h1x : (1/x) > 0, from one_div_pos_of_pos hx,
    have h1 := unb (1/x) h1x,
    rcases h1 with nx, n, hn, h2,
    use n,
    sorry, },
  { sorry, },
end

view this post on Zulip Mario Carneiro (Mar 15 2020 at 01:47):

you can use rfl instead of hn

view this post on Zulip Daniel Keys (Mar 15 2020 at 01:47):

@Bryan Gin-ge Chen Right, I didn't know how to work with the set membership relation to get it.

view this post on Zulip Daniel Keys (Mar 15 2020 at 01:48):

Thank you!

view this post on Zulip Daniel Keys (Mar 15 2020 at 15:22):

Another little bump in the other direction apparently. Does anyone see a nice way to go past that existsi line in a nice way that wouldn't need a proof for h2n?

import data.real.basic

def unboundedAbove (A : set ) :=  x : , x > 0   a  A, x < a
def archimPrinciple :=  x : , x > 0    n : , (1/n : ) < x
lemma nats_unboundedAbove_eq_arc :
    unboundedAbove {x :  |  n : , x = n}  archimPrinciple :=
begin
    split,
    -- left-right implication
    {sorry, -- this works
    },
    -- right-left implication
    intros arc x hx,
    have h1x : (1/x) > 0, from one_div_pos_of_pos hx,
    have h1 := arc (1/x) h1x,
    cases h1 with n hn,
    use n, split,
    existsi n, refl,      -- any nice solution from here?
    set xn :  := n with hxn,
    have h2n : 0 < xn, from sorry,    -- without a need for this h2n?
    exact lt_of_one_div_lt_one_div h2n hn,    -- wants h2n with xn, not ↑n --??
    done
end

view this post on Zulip Kevin Buzzard (Mar 15 2020 at 15:59):

I don't think the goal is solvable. n can be zero.

view this post on Zulip Kevin Buzzard (Mar 15 2020 at 15:59):

1/0=0 in Lean

view this post on Zulip Daniel Keys (Mar 15 2020 at 17:04):

You're right. I need to restrict my naturals to >=1 only, for this to work.

view this post on Zulip Kevin Buzzard (Mar 15 2020 at 17:17):

Aah, the good old British naturals.

view this post on Zulip Daniel Keys (Mar 15 2020 at 17:37):

Also the ones I grew up with. Base case for proof by induction was n=1 in my young years.

view this post on Zulip Viktoriya Malyasova (Mar 16 2020 at 06:52):

Hi everyone! I've worked through first 7 chapters of "Theorem proving in lean", but can't understand how pattern matching works, e.g. how to solve the first exercise in chapter 8. How do you pattern-match an expression like ∀ (b : β), ∃ (a : α), f a = b? Can I find some similar examples somewhere? In the chapter there are no examples with a universal quantifier.

view this post on Zulip Kenny Lau (Mar 16 2020 at 06:55):

bnot_bnot is an example with a universal quantifier

view this post on Zulip jack (Mar 16 2020 at 12:17):

Is anybody familiar with first order login in LEAN?

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:17):

See Flypitch

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:17):

https://github.com/flypitch/flypitch

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:18):

Corollary: @Floris van Doorn and @Jesse Michael Han are familiar with FOL in Lean

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:18):

(There might be others :wink:)

view this post on Zulip jack (Mar 16 2020 at 12:18):

Thanks Johan, but im doing my homework :(

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:19):

Aha... so what is your question?

view this post on Zulip jack (Mar 16 2020 at 12:19):

How to prove ¬ (∀ x, P x) → (∃ y, ¬ P y) :=

view this post on Zulip jack (Mar 16 2020 at 12:19):

I'm stucking at how to deal with \not \forall.

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:19):

Do you have mathlib?

view this post on Zulip jack (Mar 16 2020 at 12:20):

nope

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:20):

jack said:

I'm stucking at how to deal with \not \forall.

Aha, there must be a lemma called just like that not_forall.

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:20):

Does #check classical.not_forall give you output?

view this post on Zulip jack (Mar 16 2020 at 12:22):

open classical
#check classical.not_forall

gives me unknown identifier 'classical.not_forall'

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:22):

Hmmm, that's probably already mathlib

view this post on Zulip jack (Mar 16 2020 at 12:23):

I'm writing my homework at https://leanprover.github.io/live/latest/

view this post on Zulip jack (Mar 16 2020 at 12:23):

Noob for LEAN.

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:27):

Have you tried to use classical.by_contradiction?

view this post on Zulip jack (Mar 16 2020 at 12:31):

I'm supposed to use that, from the description of the question.

view this post on Zulip jack (Mar 16 2020 at 12:32):

Actually I have no idea how to use it.

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:33):

Are you allowed to use tactic mode?

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:33):

begin ... end blocks?

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:33):

Or are you forced to hand in term-mode proofs?

view this post on Zulip jack (Mar 16 2020 at 12:33):

yes!

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:34):

Yes to what?

view this post on Zulip jack (Mar 16 2020 at 12:34):

In the first saw I was thinking that such a LEAN is so stupid, because I have to write the proof by hand.

view this post on Zulip jack (Mar 16 2020 at 12:34):

yes with begin..end

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:35):

Ok, so

  assume H,
  apply classical.by_contradiction,

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:35):

That should get you started.

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:37):

Just follow your nose. If you get stuck, write

  apply classical.by_contradiction,

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:37):

If you have the feeling that you are going in circles, follow your other nose :stuck_out_tongue_wink:

view this post on Zulip jack (Mar 16 2020 at 12:39):

But I still have no idea how to use apply .... I have never seen that before in the class.

view this post on Zulip jack (Mar 16 2020 at 12:39):

Actually the question is quite stupid..

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:40):

Aah, so maybe they don't use begin ... end in class?

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:40):

Because after assume/intro I would think that apply is the next tactic that you learn.

view this post on Zulip jack (Mar 16 2020 at 12:41):

Just begin a section and then end that.

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:42):

Ok, so no tactic mode.

view this post on Zulip jack (Mar 16 2020 at 12:42):

I remember it's section..end not begin..end. Sorry my fault.

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:42):

In that case, start with

assume H, classical.by_contradiction $
_

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:43):

Put your cursor on the _ to see the updated goal state.

view this post on Zulip jack (Mar 16 2020 at 12:45):

It always complains
```
type mismatch, term
λ (s1 : ¬∀ (x : U), P x) (a : U) (s2 : ¬P a), by_contradiction ?m_2[s1, a, s2]
has type
Π (s1 : ¬∀ (x : U), P x) (a : U) (s2 : ¬P a), ?m_1[s1, a, s2]
but is expected to have type
(¬∀ (x : U), P x) → (∃ (y : U), ¬P y)


view this post on Zulip jack (Mar 16 2020 at 12:47):

I guess the fist step must be assume h : ¬ ∀ x, P x

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:47):

example {X} (P : X  Prop) : ¬ ( x, P x)  ( y, ¬ P y) :=
assume h, classical.by_contradiction $
_

Doesn't complain for me.

view this post on Zulip jack (Mar 16 2020 at 12:51):

Then I want assume (¬∃ (y : U), ¬P y) :anguished: just next line ?

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:52):

assume h', _

view this post on Zulip jack (Mar 16 2020 at 12:53):

type mismatch, term
λ (h : ¬∀ (x : U), P x), by_contradiction
has type
Π (h : ¬∀ (x : U), P x), (¬?m_1[h] → false) → ?m_1[h]
but is expected to have type
(¬∀ (x : U), P x) → (∃ (y : U), ¬P y)

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:53):

Please post your code

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:54):

You have a syntax error, but I can't guess it from here

view this post on Zulip Reid Barton (Mar 16 2020 at 12:54):

by_contradiction needs an argument. You can put _ for now

view this post on Zulip jack (Mar 16 2020 at 12:58):

It gives out

view this post on Zulip jack (Mar 16 2020 at 12:58):

h : ¬∀ (x : X), P x
⊢ (¬∃ (y : X), ¬P y) → false

So what's next :cold_sweat:

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:59):

No

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:59):

Post all your code

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:59):

Not the goal state

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:59):

I already told you what is next

view this post on Zulip jack (Mar 16 2020 at 12:59):

example {X} (P : X → Prop) : ¬ (∀ x, P x) → (∃ y, ¬ P y) :=
assume h, classical.by_contradiction $
_

view this post on Zulip Johan Commelin (Mar 16 2020 at 12:59):

Replace the _ with

assume H, _

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:00):

After that, put your cursor on the _ and see what the goal state is.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:00):

(By the way, which course is this?)

view this post on Zulip jack (Mar 16 2020 at 13:00):

OK I got you. One question please, what does $ mean?

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:01):

foo $ bar x y z is the same as foo (bar x y z)

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:01):

It saves you some parentheses

view this post on Zulip jack (Mar 16 2020 at 13:01):

Logic and Computation

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:01):

Uni?

view this post on Zulip jack (Mar 16 2020 at 13:01):

Birmingham

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:01):

Which?

view this post on Zulip jack (Mar 16 2020 at 13:03):

So difficult to me :(, especially the LEAN part.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:03):

So, what does the next goal state say?

view this post on Zulip jack (Mar 16 2020 at 13:04):

h1 : ¬∀ (x : X), P x,
h2 : ¬∃ (y : X), ¬P y
⊢ false

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:04):

Great, so what do you do?

view this post on Zulip jack (Mar 16 2020 at 13:04):

assume t : X and specify h2?

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:05):

Nope, you can't assume at this point

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:05):

You've got the h2 by contradiction, so using that right now would undo all the hard work

view this post on Zulip jack (Mar 16 2020 at 13:05):

~Why not?~

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:06):

Because assume only works if your goal is of the form X -> Y

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:06):

But false isn't like that.

view this post on Zulip jack (Mar 16 2020 at 13:07):

Then what about exists.intro?

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:07):

No, that only works if your goal is of the form \exists x, ...

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:07):

You need to build a term of type false.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:08):

So if you have a function of the form h1 : foobar -> false, then you could use that.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:08):

You happen to have exactly such an h1 in you list of assumptions, only the -> false is hidden by notation.

view this post on Zulip jack (Mar 16 2020 at 13:09):

Teacher says ¬ A is A → false

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:09):

So I suggest that you write h1 $ _ in place of the final underscore.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:09):

jack said:

Teacher says ¬ A is A → false

Exactly!

view this post on Zulip jack (Mar 16 2020 at 13:10):

The goal moves to ∀ (x : X), P x. Does that mean I can assume t : X now?

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:11):

Yep, now you are in good shape!

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:11):

Replace the final underscore by assume x, _

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:12):

After that, you'll need to build a term of type P x.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:12):

Or P t, if you wrote assume t

view this post on Zulip jack (Mar 16 2020 at 13:12):

Now I should elim exists..

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:12):

How?

view this post on Zulip jack (Mar 16 2020 at 13:13):

image.png

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:13):

That only works if you have h2' : \exists y, ... as an assumption. But you don't.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:13):

Your h2 has a \not in front of the exists.

view this post on Zulip jack (Mar 16 2020 at 13:14):

I have \not \exists ..., just like h1 in the example.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:14):

Sure, but the example doesn't use exists.elim either.

view this post on Zulip jack (Mar 16 2020 at 13:15):

Then it must be exists.intro :yum:

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:15):

Well.... that works if the goal is of the form \exists y, .... Which it isn't.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:16):

To summarise... you're about as stuck as you were at the beginning of your proof.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:16):

What did you do to get unstuck?

view this post on Zulip jack (Mar 16 2020 at 13:16):

by_contradiction!

view this post on Zulip jack (Mar 16 2020 at 13:19):

Then type error again...

view this post on Zulip jack (Mar 16 2020 at 13:19):

example {X} (P : X → Prop) : ¬ (∀ x, P x) → (∃ y, ¬ P y) :=
assume h1, classical.by_contradiction $
assume h2,
h1
(
assume x,
assume h3, classical.by_contradiction $
_
)

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:20):

Sure, assume h3 gives the error

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:20):

In the beginning of your proof you didn't get stuck at the 1st step. Only at the 2nd...

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:21):

So you shouldn't copy the assume .. from the beginning of the proof. Only the by_contra

view this post on Zulip jack (Mar 16 2020 at 13:21):

If i remove the assume, it comes to ¬P x → false

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:21):

Progress!

view this post on Zulip jack (Mar 16 2020 at 13:22):

Then write a h2 to make the form -> false

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:22):

Not so fast

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:22):

h2 only works if your goal is false

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:22):

But your goal is of the form X -> Y

view this post on Zulip jack (Mar 16 2020 at 13:23):

Ok now we assume.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:23):

assume hPx

view this post on Zulip jack (Mar 16 2020 at 13:24):

.. and write a h2

view this post on Zulip jack (Mar 16 2020 at 13:26):

..and then exists.introOh my god !

view this post on Zulip jack (Mar 16 2020 at 13:27):

Thank you very much ! Appreciate your help!

view this post on Zulip jack (Mar 16 2020 at 13:27):

Very kind of you!

view this post on Zulip jack (Mar 16 2020 at 13:28):

Are you the developer of LEAN?

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:28):

Nope, lol

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:28):

Just a random user

view this post on Zulip jack (Mar 16 2020 at 13:30):

I've no idea whether I can get the credit using such advanced grammar.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:30):

But you didn't right?

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:31):

Without by_contra you can't do this

view this post on Zulip jack (Mar 16 2020 at 13:32):

Yes, thats why exactly it does not mention intuitionistic logic in this question.

view this post on Zulip jack (Mar 16 2020 at 13:33):

I'm sure there must be sth. wrong with my hand-made provement.

view this post on Zulip jack (Mar 16 2020 at 13:34):

One more question, is classical.by_contradiction equivalent to A <-> ~~A?

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:36):

Yup

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:36):

Which results from classical.* were you allowed to use?

view this post on Zulip jack (Mar 16 2020 at 13:37):

I have very very few examples in the class.

view this post on Zulip jack (Mar 16 2020 at 13:37):

https://gist.github.com/benediktahrens/a52dc0137db2e845bb96b5f67645bad7

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:38):

https://gist.github.com/benediktahrens/a52dc0137db2e845bb96b5f67645bad7#file-lec9-lean-L250

view this post on Zulip jack (Mar 16 2020 at 13:38):

So i have no idea how to deal with \not at all.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:38):

uses by_contradiction

view this post on Zulip jack (Mar 16 2020 at 13:39):

Yeah. But I still don't know how to use is ... until NOW.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:40):

#check classical.by_contradiction
-- classical.by_contradiction : (¬?M_1 → false) → ?M_1

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:40):

Does that help?

view this post on Zulip jack (Mar 16 2020 at 13:40):

Thanks again for your kindly help.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:41):

So it is exactly: "prove A by proving \not \not A"

view this post on Zulip jack (Mar 16 2020 at 13:41):

Actually I ve no idea about the type signature, i.e. ?M_

view this post on Zulip jack (Mar 16 2020 at 13:42):

I thought it is just lambda calculus, that's all. The goal is really really helpful.

view this post on Zulip jack (Mar 16 2020 at 13:42):

But still, the error message is quite confusing, especially for beginners.

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:42):

?M_1 is just a weird way of writing A or P

view this post on Zulip Johan Commelin (Mar 16 2020 at 13:43):

It's a "metavariable"

view this post on Zulip jack (Mar 16 2020 at 13:45):

Are u a mathematician @Johan Commelin ?

view this post on Zulip Bryan Gin-ge Chen (Mar 16 2020 at 13:45):

It looks nicer if you write #check @classical.by_contradiction:

classical.by_contradiction :  {p : Prop}, (¬p  false)  p

The @ tells Lean to make all arguments explicit. Along the way the metavariables get nicer names.

view this post on Zulip jack (Mar 16 2020 at 13:46):

Thank u guys!

view this post on Zulip Donald Sebastian Leung (Mar 16 2020 at 14:01):

jack said:

Are u a mathematician Johan Commelin ?

Yes - in fact, he is one of the three mathematicians (the other two being Kevin Buzzard and Patrick Massot) who formalized perfectoid spaces in Lean

(Correct me if I am wrong)

view this post on Zulip jack (Mar 16 2020 at 14:10):

WOW My pleasure!

view this post on Zulip Viktoriya Malyasova (Mar 16 2020 at 14:28):

Kenny Lau said:

bnot_bnot is an example with a universal quantifier

Okay, okay, I'm wrong, still, can I see any other examples somewhere? I don't want to do case analysis on b like in the example, I want to do the analogue of intros b.

view this post on Zulip Viktoriya Malyasova (Mar 16 2020 at 14:37):

Виктория Малясова said:

Kenny Lau said:

bnot_bnot is an example with a universal quantifier

Okay, okay, I'm wrong, still, can I see any other examples somewhere? I don't want to do case analysis on b like in the example, I want to do the analogue of intros b.

Never mind, figured it out.

view this post on Zulip Yury G. Kudryashov (Mar 16 2020 at 19:36):

@Виктория Малясова What exactly do you want to do: do you want to apply a hypothesis with a universal qualifier, or to prove a goal? BTW, if you'll transliterate your nickname, more people will be able to read it, and it'll be easier to tag you in a reply.

view this post on Zulip Yury G. Kudryashov (Mar 16 2020 at 19:36):

BTW, welcome to the club.

view this post on Zulip Yury G. Kudryashov (Mar 16 2020 at 19:38):

If you want to use h : ∀ b, ∃ x, ..., then you can use something like let ⟨x, hx⟩ := h b in ....

view this post on Zulip Yury G. Kudryashov (Mar 16 2020 at 19:38):

If you want to prove ∀ b, ∃ x, P x, then you can use something like assume b, ⟨x, hx⟩

view this post on Zulip Yury G. Kudryashov (Mar 16 2020 at 19:39):

(or λ b instead of assume b)

view this post on Zulip Daniel Keys (Mar 16 2020 at 22:23):

Can anyone please point me to where the (proof of the) division algorithm a = b * q + r is hiding?

view this post on Zulip Mario Carneiro (Mar 16 2020 at 22:25):

I guess that would be a combination of the definition of nat.div and nat.mod, and nat.mod_add_div

view this post on Zulip Daniel Keys (Mar 16 2020 at 22:26):

Thanks! OK, so we don't have a stand-alone proof of it? That explains why I was searching in vain.

view this post on Zulip Daniel Keys (Mar 16 2020 at 22:34):

Although nat is strange, since I expected it to be an int thing.

view this post on Zulip Mario Carneiro (Mar 16 2020 at 22:36):

there is an int version too, but most int theorems reduce to nat counterparts

view this post on Zulip Mario Carneiro (Mar 16 2020 at 22:37):

the int version is more complicated because the modulus can be negative and conventions differ on what to do about that

view this post on Zulip Shing Tak Lam (Mar 17 2020 at 13:25):

Hello, I'm struggling with getting rewrite to do what I want it to do, I have (extra goals removed)

hn2 : n % 2 = 1,
 n = 1 + 2 * (n / 2)

and I want to rewrite it to

 n = n % 2 + 2 * (n / 2)

But if I use rw <-hn2 it gives me

 n = n % 2 + bit0 (n % 2) * (n / bit0 (n % 2))

as it replaces 2 with bit0 (n % 2)

Thank you!

view this post on Zulip Kevin Buzzard (Mar 17 2020 at 13:29):

ha ha! This is happening because of the way numerals are internally stored (2 = bit0 1). There are ways around this.

view this post on Zulip Kevin Buzzard (Mar 17 2020 at 13:31):

example (n : ) (hn2 : n % 2 = 1) : n = 1 + 2 * (n / 2) :=
begin
  conv begin
    -- entering "conv mode" where we can pull terms off the goal
    to_rhs,
    congr,
    -- now we have the 1
    rw hn2, -- rewrite succeeds
  end,
  -- done
  sorry
end

view this post on Zulip Kevin Buzzard (Mar 17 2020 at 13:32):

here is more information about conv.

view this post on Zulip Kevin Buzzard (Mar 17 2020 at 13:34):

Here is a more direct approach:

example (n : ) (hn2 : n % 2 = 1) : n = 1 + 2 * (n / 2) :=
begin
  conv in (1) begin
    rw hn2,
  end,
  sorry
end

view this post on Zulip Shing Tak Lam (Mar 17 2020 at 13:34):

Yeah I see. So numerals are stored in binary in reverse order? That seems fascinating and I remember playing around with that in Haskell. Makes sense that Lean would use that.

Anyways, this seemed to work

have hnm': 1 + 2 * (n / 2) = n % 2 + 2 * (n / 2) := by rw hn2,
rw hnm',

Thanks a lot!

view this post on Zulip Kevin Buzzard (Mar 17 2020 at 13:36):

Yes, your approach should also work. Nice!

Yes, Lean internally stores numerals as bit0 (bit1 (bit1 (...))). You can see what's going on internally with the option set_option pp.numerals false.

view this post on Zulip Shing Tak Lam (Mar 17 2020 at 16:10):

Alright, thanks a lot.

Another question, is there a way to paste the highlighted value from Ctrl-P # to the location of the cursor? For example with a lemma that has a long name (such as div_le_div_of_le_of_pos), after finding it I press enter to go to the file and I copy the name from there. Is there a quicker way?

Thanks!

view this post on Zulip Bryan Gin-ge Chen (Mar 17 2020 at 16:18):

Not at the moment, but that's an interesting feature request. Please open an issue here.

view this post on Zulip Shing Tak Lam (Mar 17 2020 at 16:19):

Alright thanks. Will do.

view this post on Zulip Kevin Buzzard (Mar 17 2020 at 16:32):

If you find the lemma by typing div_le_div and then pressing ctrl-space and scrolling down the options with the arrow keys then you can complete with tab and there it is

view this post on Zulip Kevin Buzzard (Mar 17 2020 at 16:32):

Press ctrl-space a second time to see the full types

view this post on Zulip Shing Tak Lam (Mar 18 2020 at 05:48):

Alright thanks. That doesn't work all the time for me though, but I think it's an issue with my VSCode installation rather than with the Lean extension.

view this post on Zulip Shing Tak Lam (Mar 18 2020 at 05:52):

Another question, how do I prove this?

(r is a nat)

(2 * r + 1) % 2 = 1

I've found a few things that are interesting in int., but nothing came up when looking in nat, and searching for combinations of add, mul and mod didn't give anything. I guess what I'm looking for is

a < b -> (b * n + a) % b = a

view this post on Zulip Bryan Gin-ge Chen (Mar 18 2020 at 05:52):

The VS Code extension queries Lean for autocomplete information and sadly Lean doesn't always provide anything useful at a given position in a file. If you have some specific examples we can take a look.

view this post on Zulip Bryan Gin-ge Chen (Mar 18 2020 at 06:04):

This is what I get after trying suggest:

import tactic

example (a b n: ) :
a < b -> (b * n + a) % b = a := begin
  refine norm_num.nat_mod_helper (b * n + a) b n a _,
  ring,
end

Surely there's a way to do this without pulling in something written for norm_num though.

view this post on Zulip Mario Carneiro (Mar 18 2020 at 06:48):

example (a b n: ) (h : a < b) : (b * n + a) % b = a :=
by rw [add_comm, nat.add_mul_mod_self_left, nat.mod_eq_of_lt h]

view this post on Zulip Kenny Lau (Mar 18 2020 at 06:50):

import tactic.norm_num

example (r : ): (2 * r + 1) % 2 = 1 :=
by rw [add_comm, nat.add_mul_mod_self_left]; norm_num

view this post on Zulip Kenny Lau (Mar 18 2020 at 06:50):

lol you're faster

view this post on Zulip Shing Tak Lam (Mar 18 2020 at 06:57):

Thank you all!

view this post on Zulip Daniel Keys (Mar 20 2020 at 19:18):

Could someone please help with the last sorry in this proof? I expect I need revert or maybe generalize. I don't know how to move along with either, though!

import data.real.basic

def sum_of_sets (A : set ) (B : set ) := { x :  |  y  A,  z  B, x = y + z}
lemma proposition_2_6 (A : set ) (B : set ) (h1A : A.nonempty) (h1B : B.nonempty)
  (h2A : bdd_above A) (h2B : bdd_above B) (a : ) (b : ) :
  (is_lub A a)  (is_lub B b)  is_lub (sum_of_sets A B) (a + b) :=
begin
  intro h,
  cases h with hA hB,
  split,
  { sorry,  -- this side works
  },
  -- now prove that (a+b) is the least upper bound
  intros S hS,
  change  xab  (sum_of_sets A B), xab  S at hS,
  --cases h1A with ya hya,
  cases h1B with z hz,
  have H1 :  y  A, (y + z)  (sum_of_sets A B),
    intros y hy,
    unfold sum_of_sets,
    existsi y, existsi hy, existsi z, existsi hz, refl,
  have H2 :  y  A, (y + z)  S,
    intros y hy,
    apply hS, exact H1 y hy,
  have H3 :  y  A, y  S - z,
    intros y hy,
    have H3a := H2 y hy,
    linarith,
  have H4 : (S - z)  upper_bounds A, exact H3,
  have H5 : a  (S - z),
    have H13A := hA.right,
    have h13 := H13A H4, exact h13,
  have H6 : z  S - a, linarith,
  have H7 : (S - a)  upper_bounds B,  -- got stuck here
    --revert z,
    --does generalize work? How?
   sorry,
end

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:27):

z is now a fixed real number in B. In particular you only know that t <= S - a for one particular t in B, namely t = z. You can make progress in the proof with intros t ht, but that is basically your only next move. You can't use z to prove the goal.

view this post on Zulip Daniel Keys (Mar 20 2020 at 19:35):

I thought I could move on by reverting z. So I'm wrong there?

view this post on Zulip Daniel Keys (Mar 20 2020 at 19:40):

I should be able to use the fact that the initial z was chosen arbitrarily. I also thought about starting with forall z at the very top, but am just trying to follow one of the standard proofs - and learn some more Lean in the process!

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:45):

But z is not arbitrary, z is one specific element of B which is the witness to the non-emptiness of B.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:46):

h1B is like saying "this specific constant real number z is an element of B". It's no different to saying "assume πB\pi\in B". You can prove whatever you like about π\pi now, but you won't be able to deduce anything about an arbitrary element of BB.

view this post on Zulip Daniel Keys (Mar 20 2020 at 19:47):

OK. So I'm not supposed to be thinking about it as arbitrary? Then I need to rewrite from the start I guess.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:47):

Yes it's definitely not arbitrary, it's some fixed constant.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:50):

hB has, buried within it, a statement about an arbitrary element of B.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:54):

I set this question in an undergraduate exam in 2018 and @Abhimanyu Pallavi Sudhir formalised the solutions. @Kenny Lau sat the exam and his written solution was constructive and could be basically cut and pasted into Lean. It was funny reading it. He kept writing assume :-)

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:56):

You need to be proving things like this:

  have H2 :  y  A,  z  B, (y + z)  S,
    intros y hy z hz,
    apply hS, use y, split, use hy, use z, split, use hz, refl,

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 19:56):

sorry for ugly proof, just got to run

view this post on Zulip Daniel Keys (Mar 20 2020 at 20:04):

Kevin Buzzard said:

You need to be proving things like this:

  have H2 :  y  A,  z  B, (y + z)  S,
    intros y hy z hz,
    apply hS, use y, split, use hy, use z, split, use hz, refl,

Right. This is what I meant by starting over. Thanks again for the help! Hopefully I get there in another day or so -:)

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 20:39):

have H2 : ∀ y ∈ A, ∀ z ∈ B, (y + z) ≤ S := λ y hy z hz, hS _ ⟨y, hy, z, hz, rfl⟩,

view this post on Zulip Daniel Keys (Mar 20 2020 at 20:47):

Yes, I have changed all that and now I get stuck here:

-- now prove that (a+b) is the least upper bound
  intros S hS,
  change  xab  (sum_of_sets A B), xab  S at hS,
  have H1 :  y  A,  z  B, (y + z)  (sum_of_sets A B),
    intros y hy z hz,
    unfold sum_of_sets,
    existsi y, existsi hy, existsi z, existsi hz, refl,
  have H2 :  y  A,  z  B, (y + z)  S,
    intros y hy z hz,
    apply hS, exact H1 y hy z hz,
  have H3 :  y  A,  z  B, y  S - z,
    intros y hy z hz,
    have H3a := H2 y hy z hz,
    linarith,
  have h21B := hB.right, have h22B := hB.left,
  change  z  B, z  b at h22B,
  have H4 :  y  A,  z  B, (S - z)  upper_bounds A, --!
    intros y hy z hz,
    have H4a := h22B z hz,
    have H4b := H3 y hy z hz,
    change  y  A, y  (S - z),   -- exact H4b doesn't do it

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 20:50):

The y : ℝ is a constant. Your goal has a variable y in.

view this post on Zulip Daniel Keys (Mar 20 2020 at 20:50):

Failing to see the same thing again, huh?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 20:51):

Your H4 has a superfluous y in

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 20:51):

the conclusion of H4 doesn't mention y, so you're still on track

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 20:52):

yeah this is fine, your H4 is just not correctly stated.

view this post on Zulip Daniel Keys (Mar 20 2020 at 20:56):

OK, that helped. I'm past it now.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:02):

  intros S hS,
  have H3 :  y  A,  z  B, y  S - z :=
    λ y hy z hz, le_sub_right_of_add_le $ hS y, hy, z, hz, rfl,

Here's how I would skip H1 and H2 and prove H3 in term mode.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:03):

have h21B := hB.right, have h22B := hB.left, could just be cases hB with h22B h21B,, although note that the latter destroys hB.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:05):

Try commenting out all the lines which mention change. Interesting, huh?

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:17):

Yes - it's still useful for me at this stage to see things explicitly.
You were right, setting up your own problems teaches you a lot! If you also get some help...

Now here's where I'm right now, I literally have it - but Lean doesn't think so!

intros S hS,
  have H1 :  y  A,  z  B, (y + z)  (sum_of_sets A B),
    intros y hy z hz,
    unfold sum_of_sets,
    existsi y, existsi hy, existsi z, existsi hz, refl,
  have H2 :  y  A,  z  B, (y + z)  S,
    intros y hy z hz,
    apply hS, exact H1 y hy z hz,
  have H3 :  y  A,  z  B, y  S - z,
    intros y hy z hz,
    have H3a := H2 y hy z hz,
    linarith,
  have h21B := hB.right, have h22B := hB.left,
  --change ∀ z ∈ B, z ≤ b at h22B,
  have H4 :  z  B, (S - z)  upper_bounds A, --!
    intros z hz y hy,
    exact H3 y hy z hz,
  have H5 :  z  B, a  (S - z),
    intros z hz,
    have H13A := hA.right,
    change  u  upper_bounds A, a  u at H13A,
    have H5a := H4 z hz,   -- can't get to use H13A at all

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:18):

Oh, wait

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:19):

Done.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:19):

proof script or it didn't happen

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:19):

What is this proving?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:20):

sup S + sup T = sup (S+T)

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:20):

I mean: what is the Lean statement?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:20):

def sum_of_sets (A : set ) (B : set ) := { x :  |  y  A,  z  B, x = y + z}
lemma proposition_2_6 (A : set ) (B : set ) (h1A : A.nonempty) (h1B : B.nonempty)
  (h2A : bdd_above A) (h2B : bdd_above B) (a : ) (b : ) :
  (is_lub A a)  (is_lub B b)  is_lub (sum_of_sets A B) (a + b) :=

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:21):

The proof can't possibly start with intros S hS

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:22):

Kevin Buzzard said:

proof script or it didn't happen

I have H5 : ∀ z ∈ B, a ≤ (S - z). Still a little ways to go.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:22):

begin
  intro h,
  cases h with hA hB,
  split,
  { sorry,  -- this side works
  },
  -- now prove that (a+b) is the least upper bound

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:22):

Daniel Keys said:

I have H5 : ∀ z ∈ B, a ≤ (S - z). Still a little ways to go.

Oh! I'm rooting for you :-)

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:22):

I'm making some other proofs

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:24):

Patrick, we're just talking about this part:

lemma proposition_2_6'' (A : set ) (B : set ) (h1A : A.nonempty) (h1B : B.nonempty)
  (h2A : bdd_above A) (h2B : bdd_above B) (a : ) (b : )
  (hA : is_lub A a) (hB : is_lub B b) :
  a + b  lower_bounds (upper_bounds (sum_of_sets A B)) :=

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:26):

How can it be that complicated?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:27):

He's a beginner!

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:28):

We're going to refactor after.

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:28):

Ok, I should go to the PR and issues lists.

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:34):

Kevin Buzzard said:

proof script or it didn't happen

OK now, this is the finish. Uncountable thanks, Kevin!

have H5 :  z  B, a  (S - z),
    intros z hz,
    have H13A := hA.right,
    change  u  upper_bounds A, a  u at H13A,
    have H5a := H4 z hz,
    exact H13A (S-z) H5a,
  have H6 :  z  B, z  S - a,
    intros z hz,
    have H6a := H5 z hz, linarith,
  have H7 : (S - a)  upper_bounds B, exact H6,
  have H8 : b  (S-a),
    have H13B := hB.right,
    change  u  upper_bounds B, b  u at H13B,
    exact H13B (S-a) H7,
  linarith, done

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:34):

lemma proposition_2_6''' (A : set ) (B : set ) (a : ) (b : )
  (hA : is_lub A a) (hB : is_lub B b) :
  a + b  lower_bounds (upper_bounds (sum_of_sets A B)) :=
λ S hS, add_le_of_le_sub_left $ hB.2 $ λ z hz, le_sub.1 $ hA.2 $ λ y hy, le_sub_right_of_add_le $ hS y, hy, z, hz, rfl

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:35):

Still need to work on term mode. On my to do list.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:35):

So do you want to refactor your proof to make it much shorter?

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:36):

Meaning?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:37):

do you want me to show you how to think about your proof so that the next time you have to write such a proof it will come out better, shorter, and will compile quicker?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:37):

lemma proposition_2_6' (A : set ) (B : set ) (h1A : A.nonempty) (h1B : B.nonempty)
  (h2A : bdd_above A) (h2B : bdd_above B) (a : ) (b : )
  (hA : is_lub A a) (hB : is_lub B b) :
  a + b  lower_bounds (upper_bounds (sum_of_sets A B)) :=
begin
  intros S hS,
  have H1 :  y  A,  z  B, (y + z)  (sum_of_sets A B),
    intros y hy z hz,
    unfold sum_of_sets,
    existsi y, existsi hy, existsi z, existsi hz, refl,
  have H2 :  y  A,  z  B, (y + z)  S,
    intros y hy z hz,
    apply hS, exact H1 y hy z hz,
  have H3 :  y  A,  z  B, y  S - z,
    intros y hy z hz,
    have H3a := H2 y hy z hz,
    linarith,
  have h21B := hB.right, have h22B := hB.left,
  --change ∀ z ∈ B, z ≤ b at h22B,
  have H4 :  z  B, (S - z)  upper_bounds A, --!
    intros z hz y hy,
    exact H3 y hy z hz,
have H5 :  z  B, a  (S - z),
    intros z hz,
    have H13A := hA.right,
    change  u  upper_bounds A, a  u at H13A,
    have H5a := H4 z hz,
    exact H13A (S-z) H5a,
  have H6 :  z  B, z  S - a,
    intros z hz,
    have H6a := H5 z hz, linarith,
  have H7 : (S - a)  upper_bounds B, exact H6,
  have H8 : b  (S-a),
    have H13B := hB.right,
    change  u  upper_bounds B, b  u at H13B,
    exact H13B (S-a) H7,
  linarith,
end

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:37):

Of course.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:38):

That's your proof currently. I tidied up the beginning -- I removed the sorry and I did the intro and cases (I changed the goal a bit so hA and hB are now hypotheses and I changed the conclusion so it was just the goal you were working on)

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:39):

Right, I did see that.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:39):

So the thing I like least about your proof is the linariths

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:40):

I mean, it's great that linarith exists and can do all sorts of linear inequalities, but when you use it you're using a sledgehammer to crack a nut.

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:40):

OK, I did those since I know how to deal with those goals.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:40):

The first time you use it is about 11 lines into your proof.

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:40):

But I agree with you.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:41):

Your local context is

...
H3a : y + z ≤ S
⊢ y ≤ S - z

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:41):

and you solve this with linarith

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:41):

So I look at that and think "that is a completely standard fact so it's going to be in the library"

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:42):

Yes, agreed. Just lazy, there were bigger fish...

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:42):

The problem is, I don't know whether it's going to be y + z ≤ S -> y ≤ S - z or y ≤ S - z <-> y ≤ S - z in the library, and I don't know the name of the lemma either.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:43):

But if you know the tricks, you can sort this out really easily.

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:43):

library_search? I also browse through files many times.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:43):

You don't need anything like that

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:44):

you can do this just with VS Code tricks. Your goal is y <= S - z and so the Lean name for the theorem you want will start le_sub

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:44):

so you can replace that first linarith with exact le_sub but we're not finished yet

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:44):

sub for subtraction here?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:45):

Right. There's a code which you eventually pick up. is le, < is lt etc

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:45):

I saw lots of these in NNG, but there was no sub there. So this one's new.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:46):

If I delete that first linarith and replace it with exact le_sub then VS Code immediately gives me a list of possible completions. Does that work for you?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:47):

If it doesn't, try exact le_sub and then hit ctrl-space. This is a really important trick to learn.

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:47):

Yes, five options. Thanks for the hint!

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:47):

and you can scroll up and down with the arrow keys and see what all the suggestions are.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:48):

and le_sub_right_of_add_le is exactly what you want.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:49):

so you can hit tab and it will complete for you, and you can change that linarith to exact le_sub_right_of_add_le H3a,

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:49):

library_search would have been faster.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:49):

You'd have to revert H3 or something.

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:49):

Why?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:50):

Oh you don't have to?

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:50):

Don't underestimate the power of library_search

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:50):

For the second one we have

H6a : a ≤ S - z
⊢ z ≤ S - a

Let's try library_search

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:50):

Go back watching Gabriel's talk in Pittsburgh.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:51):

library_search doesn't give the optimal answer for the second one: exact le_sub.mp (H5 z hz)

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:51):

Patrick Massot said:

Go back watching Gabriel's talk in Pittsburgh.

Is that a video you're talking about, Patrick?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:52):

If I try exact le_sub I see that le_sub is pretty much nearly what we want, except that it's an if and only if

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:53):

and you can pull out one way of an if and only if with a .1, so

    have H6a := H5 z hz, exact le_sub.1 H6a,

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:54):

The third one is on the last line of the script, and it's

H8 : b ≤ S - a
⊢ a + b ≤ S

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:54):

and again library_search gives a terrifying answer

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:55):

but I'm going to change it to exact add_le_of_le_sub_left H8,

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:55):

so now we have this:

lemma proposition_2_6' (A : set ) (B : set ) (h1A : A.nonempty) (h1B : B.nonempty)
  (h2A : bdd_above A) (h2B : bdd_above B) (a : ) (b : )
  (hA : is_lub A a) (hB : is_lub B b) :
  a + b  lower_bounds (upper_bounds (sum_of_sets A B)) :=
begin
  intros S hS,
  have H1 :  y  A,  z  B, (y + z)  (sum_of_sets A B),
    intros y hy z hz,
    unfold sum_of_sets,
    existsi y, existsi hy, existsi z, existsi hz, refl,
  have H2 :  y  A,  z  B, (y + z)  S,
    intros y hy z hz,
    apply hS, exact H1 y hy z hz,
  have H3 :  y  A,  z  B, y  S - z,
    intros y hy z hz,
    have H3a := H2 y hy z hz,
    exact le_sub_right_of_add_le H3a,
  have h21B := hB.right, have h22B := hB.left,
  --change ∀ z ∈ B, z ≤ b at h22B,
  have H4 :  z  B, (S - z)  upper_bounds A, --!
    intros z hz y hy,
    exact H3 y hy z hz,
have H5 :  z  B, a  (S - z),
    intros z hz,
    have H13A := hA.right,
    change  u  upper_bounds A, a  u at H13A,
    have H5a := H4 z hz,
    exact H13A (S-z) H5a,
  have H6 :  z  B, z  S - a,
    intros z hz,
    have H6a := H5 z hz, exact le_sub.1 H6a,
  have H7 : (S - a)  upper_bounds B, exact H6,
  have H8 : b  (S-a),
    have H13B := hB.right,
    change  u  upper_bounds B, b  u at H13B,
    exact H13B (S-a) H7,
  exact add_le_of_le_sub_left H8,
end

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:55):

and now our proof uses only really basic tactics so it's in a really good form to play with.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:56):

Next thing: did you know that change doesn't really do anything? It's necessary for rewrites, but not for stuff like apply and intro.

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:56):

Thanks Kevin, for taking all this time! Yes, I know about change.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:57):

actually let's leave these. Let me get to the bombshell.

view this post on Zulip Daniel Keys (Mar 20 2020 at 21:57):

These are supposed to be readable by students, once I get up standing myself.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:57):

The bombshell is that your proof is twice as long as it needs to be, because you wrote it in a direction which a mathematician would call "forwards"

view this post on Zulip Patrick Massot (Mar 20 2020 at 21:57):

https://www.youtube.com/watch?v=WydyJJYKyTs&list=PLlF-CfQhukNkWwZt45vkNfWfuO-tBBqPN&index=16&t=0s explains how powerfull is library_search

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:58):

and which a computer scientist would call "the wrong way around"

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:58):

You prove 8 sub-theorems H1 to H8 and then finished the job

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:58):

Thanks @Patrick Massot

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:58):

And each H(n+1) followed from Hn

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:59):

and at the end of it your local context looks like this:

1 goal
A B : set ℝ,
h1A : set.nonempty A,
h1B : set.nonempty B,
h2A : bdd_above A,
h2B : bdd_above B,
a b : ℝ,
hA : is_lub A a,
hB : is_lub B b,
S : ℝ,
hS : S ∈ upper_bounds (sum_of_sets A B),
H1 : ∀ (y : ℝ), y ∈ A → ∀ (z : ℝ), z ∈ B → y + z ∈ sum_of_sets A B,
H2 : ∀ (y : ℝ), y ∈ A → ∀ (z : ℝ), z ∈ B → y + z ≤ S,
H3 : ∀ (y : ℝ), y ∈ A → ∀ (z : ℝ), z ∈ B → y ≤ S - z,
h21B : b ∈ lower_bounds (upper_bounds B),
h22B : b ∈ upper_bounds B,
H4 : ∀ (z : ℝ), z ∈ B → S - z ∈ upper_bounds A,
H5 : ∀ (z : ℝ), z ∈ B → a ≤ S - z,
H6 : ∀ (z : ℝ), z ∈ B → z ≤ S - a,
H7 : S - a ∈ upper_bounds B,
H8 : b ≤ S - a
⊢ a + b ≤ S

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:59):

You proved H1 -> H2 -> H3 -> H4 -> H5 -> H6 -> H7 -> H8

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 21:59):

and H8 -> goal

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:00):

Let's now write exactly the same proof, but backwards.

view this post on Zulip Daniel Keys (Mar 20 2020 at 22:00):

You mean using apply?

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:01):

lemma proposition_2_6' (A : set ) (B : set ) (h1A : A.nonempty) (h1B : B.nonempty)
  (h2A : bdd_above A) (h2B : bdd_above B) (a : ) (b : )
  (hA : is_lub A a) (hB : is_lub B b) :
  a + b  lower_bounds (upper_bounds (sum_of_sets A B)) :=
begin
  intros S hS,
  sorry
end

The goal is ⊢ a + b ≤ S

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:02):

and the last line of our current proof is exact add_le_of_le_sub_left H8, so let's make the first line of our new proof be apply add_le_of_le_sub_left,

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:02):

lemma proposition_2_6'' (A : set ) (B : set ) (h1A : A.nonempty) (h1B : B.nonempty)
  (h2A : bdd_above A) (h2B : bdd_above B) (a : ) (b : )
  (hA : is_lub A a) (hB : is_lub B b) :
  a + b  lower_bounds (upper_bounds (sum_of_sets A B)) :=
begin
  intros S hS,
  apply add_le_of_le_sub_left,
  sorry -- goal is ⊢ b ≤ S - a
end

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:02):

and now our goal is H8

view this post on Zulip Daniel Keys (Mar 20 2020 at 22:02):

OK. Let me take it from here.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:03):

Go for it! I did it, it's really good fun :-)

view this post on Zulip Daniel Keys (Mar 20 2020 at 22:03):

I have to go now, but will definitely try it later. Will haul back for help if needed.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:03):

Note that H7 and H6 are exactly the same goal!

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:03):

I don't think you need to do backwards to make it shorter.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:03):

so you can skip H7

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:04):

Patrick did you see my one line term proof? I made that by turning Daniel's proof backwards and then termifying it

view this post on Zulip Daniel Keys (Mar 20 2020 at 22:04):

Patrick Massot said:

I don't think you need to do backwards to make it shorter.

Either way is good practice for me.

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:04):

No, I haven't seen your proof term.

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:05):

But I guess it's hard to read.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:05):

https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/noob.20question%28s%29/near/191305486

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:05):

It's the same as @Daniel Keys 's proof :-)

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:05):

It looks has I expected...

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:06):

My advice for Daniel is: try to get a clearer mathematical picture.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:06):

It is super-satisfying to turn this proof backwards

view this post on Zulip Mario Carneiro (Mar 20 2020 at 22:06):

If you break that term mode proof into a couple applys and intros it should be plenty readable

view this post on Zulip Daniel Keys (Mar 20 2020 at 22:06):

Patrick Massot said:

My advice for Daniel is: try to get a clearer mathematical picture.

Why exactly, Patrick?

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:08):

I would start with

  intros S hS,
  have H1 :  x  A, S - x  upper_bounds B,
    sorry,
  have H2 : S - b  upper_bounds A,
    sorry,
  sorry,

where each sorry is at most three lines long.

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:09):

I claim this is a readable outline of the proof.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:10):

I think it's interesting that I set this question to about 250 students and out of all of them, only one person proved it constructively.

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:10):

And this does not come through Lean mastery, it's the mathematical understanding.

view this post on Zulip Mario Carneiro (Mar 20 2020 at 22:11):

what's up with these unbracketed indented blocks after have? This isn't python

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:11):

Everyone said that if some upper bound was less than a+b then you could find some element of A which was within epsilon/2 of the upper bound for A etc.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:12):

indented blocks: I thought that TPIL said that this was OK. Doesn't it?

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:12):

Mario, I can tell you very precisely where they come from.

view this post on Zulip Mario Carneiro (Mar 20 2020 at 22:12):

they have the same problem as unbracketed blocks elsewhere

view this post on Zulip Mario Carneiro (Mar 20 2020 at 22:13):

tactics can end up doing too much and messing up other branches of the proof

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:13):

https://leanprover.github.io/theorem_proving_in_lean/tactics.html?highlight=indent#basic-tactics

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:13):

Last year I taught curly brackets to my undergrads. But they were unable to balance them properly. And then Lean stopped displaying anything, or wrote very confusing error messages (which means any error message for my students). This year I taught indented blocks, and Lean became easy.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:14):

unbalanced bracket = really really horrible errors. You either get sync or you just get literally nothing. No display at any point in your proof.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:14):

Really hard to debug

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:14):

Kevin Buzzard said:

https://leanprover.github.io/theorem_proving_in_lean/tactics.html?highlight=indent#basic-tactics

And Mario adds one line to his "When he won't be my advisor anymore" notebook.

view this post on Zulip Mario Carneiro (Mar 20 2020 at 22:15):

Does anyone want to teach python to lean? I agree the error messages are terrible

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:15):

A lot of the kids know python anyway, at least mathematicians do, they are taught it at my university

view this post on Zulip Mario Carneiro (Mar 20 2020 at 22:15):

I think coq uses some kind of markdown list thing

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:17):

I like Lean's {/}, but my teaching taught me bad habits.

view this post on Zulip Patrick Massot (Mar 20 2020 at 22:18):

I need to go, so I'll post spoilers for Daniel:
.
.
.
.
.
.
.
.
.
.
.
.

  intros S hS,
  have H1 :  x  A, S - x  upper_bounds B,
  { intros x hx y hy,
    suffices : x + y  S, by linarith, -- by rwa le_sub_iff_add_le',
    exact hS x, hx, y, hy, rfl, },
  have H2 : S - b  upper_bounds A,
  { intros x hx,
    suffices : b  S - x, by linarith, -- by rwa le_sub,
    exact hB.2 (H1 x hx) },
  linarith [hA.2 H2], --exact le_sub_iff_add_le.mp (hA.2 H2),

The commented our version are only for Kevin's pleasure. I don't see any point in learning those lemmas.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:24):

I was going to see if I could take Daniel to the full term proof, and there they're important; we don't enter tactic mode at all there, so you can really see that the proof is just a function. This is kind of a startling revelation to a mathematician.

view this post on Zulip Kevin Buzzard (Mar 20 2020 at 22:43):

I don't see any point in learning those lemmas.

Another reason for showing the ctrl-space technique is that even though of course you're right that linarith will prove all of them, it is generally a very important technique, especially when you're in situations like trying to figure out how to prove a \in {a}, where what I explained is exactly how a beginner should find that proof (mem_singleton-ctrl-space)

view this post on Zulip Stephanie Zhou (Mar 21 2020 at 00:57):

How do I use e (as in Euler's number) in lean?

view this post on Zulip Mario Carneiro (Mar 21 2020 at 02:29):

I don't think e has been defined, but you can use real.exp 1 if you import data.complex.exponential

view this post on Zulip Paul van Wamelen (Mar 21 2020 at 17:41):

The following:

import data.int.gcd
import tactic

example (a b : ) (h : nat.gcd (2 * a) b = 1) : 1 = (2 * a : ) * nat.gcd_a (2 * a) b + b * nat.gcd_b (2 * a) b :=
begin
    rw nat.gcd_eq_gcd_ab (2 * a) b, simp [h]
end

fails at the rw because lean can't match ↑(2 * a) with 2 * ↑a. I can do:

example (a b : ) (h : nat.gcd (2 * a) b = 1) : 1 = (2 * a : ) * nat.gcd_a (2 * a) b + b * nat.gcd_b (2 * a) b :=
begin
    let a2 := 2 * a,
    change 1 = (a2 : ) * nat.gcd_a a2 b + b * nat.gcd_b a2 b,
    rw nat.gcd_eq_gcd_ab (2 * a) b, simp [h]
end

Is there a better way? (I should probably ask: what is the better way :smiley: )

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 17:43):

One question might be: if you're interested in integers, why are you using naturals at all?

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 17:44):

But there is a tactic which can help called norm_cast if you really want to mix your types like this

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 17:45):

I would imagine that norm_cast will turn \u(2*a) into 2*\u a

view this post on Zulip Paul van Wamelen (Mar 21 2020 at 18:00):

Ugh, I should have been able to do that myself. norm_cast works. Thanks!!
Is there an int version of gcd_eq_gcd_ab? Well, even gcd_eq_gcd_ab is in an int file. Oh, the more general statement is probably an euclidean_domain thing. I'll find it.

view this post on Zulip Daniel Keys (Mar 21 2020 at 18:25):

I have this in my context:

m : ,
h51 : 0  m - 1,
h6b : m  m - 1
 false

but am not able to satisfy the goal; linarith, dec_trivial, norm_num and everything else I tried all fail. I suppose this may be due to a type conversion problem, as m-1 may be seen as an integer by Lean. Any hint on how to proceed appreciated!

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:26):

You can't solve that goal :-(

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:26):

If m = 0 then all the hypotheses are true

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:27):

#eval (0 : ℕ) - 1 -- 0

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:27):

It's Patrick's favourite Lean fact.

view this post on Zulip Patrick Stevens (Mar 21 2020 at 18:29):

There's a good reason every introductory text I've ever seen to Peano arithmetic defines - with a superscript dot, because it's very much not the same as - :P really it's the Billion Dollar Mistake again, we (= the world) shouldn't pun between N and Maybe N in this way

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:29):

#print has_sub
/-
@[class]
structure has_sub : Type u → Type u
fields:
has_sub.sub : Π {α : Type u} [c : has_sub α], α → α → α
-/

The subtraction typeclass in Lean is a notation typeclass, and subtraction itself has type α → α → α which means that whatever you're subtracting, the two inputs and the output have to have the same type. So there's no way around it, if you want subtraction on the naturals then it has to return a natural.

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:30):

I have pushed in the past for 0 - 1 to be 37 but the idea never gained any traction.

view this post on Zulip Daniel Keys (Mar 21 2020 at 18:31):

But things would change if I switched to int instead, right?

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:32):

Indeed

view this post on Zulip Patrick Stevens (Mar 21 2020 at 18:32):

The Real Problem (tm) is that - just doesn't (morally) have type N -> N -> N; is there a good reason why it has that type in Lean?

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:32):

I would not be arguing that the integer 0-1 should be 37

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:32):

The answer used to be "because it's in core and we can't change core"

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:33):

but even now it could be changed in theory, the CS people won't let you change it because they read the same books on Peano arithmetic that you did and they liked it

view this post on Zulip Patrick Stevens (Mar 21 2020 at 18:34):

There are many places where I have strong opinions but recognise that reasonable people may reasonably differ; but this is not one of them

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:34):

A subtraction of the form A -> A -> B would probably cause a lot more problems than it solved.

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:35):

For example if you wanted to prove a - b + b = a then there are problems because suddenly a -b has type B (or int or whatever) so now when you add b (which has type nat) you will have to coerce, and now you end up with the integer a

view this post on Zulip Marc Huisinga (Mar 21 2020 at 18:35):

i think that this is actually a pretty common theme in lean. requiring functions to be partial often results in needing lots of plumbing. instead we just define those functions to be some arbitrary value and demand some extra hypothesis in proofs to ensure that the case doesn't happen.

view this post on Zulip Daniel Keys (Mar 21 2020 at 18:35):

Kevin Buzzard said:

A subtraction of the form A -> A -> B would probably cause a lot more problems than it solved.

OK that makes sense - thanks a lot!

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:35):

As a mathematician I want to believe that these coercions don't exist, but they are there and they cause problems for the CS people.

view this post on Zulip Patrick Stevens (Mar 21 2020 at 18:35):

Kevin Buzzard said:

A subtraction of the form A -> A -> B would probably cause a lot more problems than it solved.

To me, it's "completely obvious" that if you can prove a < b, then you should be using something of type (a b : N) -> (a <= b) -> N, and otherwise you should be using (a b : N) -> Maybe N

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:36):

right -- that would be another approach, and when I started here I thought that this was manifestly the correct approach and all the CS people were crazy

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:37):

but then I tried it in practice. When I started here there was no real.sqrt and I was teaching it in my class so I defined it in Lean and I my definition took as input a real number r and a proof that it was >= 0, and then it defined the square root to be some sup

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:37):

and then a passing computer scientist came along and said "ha ha look at the silly mathematician, he is asking for an input to his function and then he never uses the input!"

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:37):

and indeed, you could just remove the hypothesis as an input and the definition compiled just fine

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:38):

and when I started thinking about it that way, I started having doubts

view this post on Zulip Patrick Stevens (Mar 21 2020 at 18:38):

But that's why God gave us the notion of irrelevance :P for when you need to tell things to the compiler which it would be annoying to express in any other way

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:38):

and then when I started formalising all my problem sheet questions, and every time I even wrote the square root I had to prove that something was non-negative, so I would constantly be proving that 2>=0 when working with sqrt(2)

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:39):

and in the end I got so sick of proving 2>=0 (this was before the days of norm_num so it wasn't even that easy) that I gave up and I dropped the hypothesis in the definition of sqrt, and instead I just put the hypothesis in the theorem statements

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:40):

because the square root of every negative integer was coming out to be 37 so I needed it in the theorem statements

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:40):

(well OK, it was coming out to be 0)

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:40):

but I was having to prove 2>=0 an order of magnitude fewer times this way

view this post on Zulip Patrick Stevens (Mar 21 2020 at 18:40):

Fair enough, though I weep to hear that things might simply have to be this way

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:40):

and then I just realised that I had defined a square root with a dot on it

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 18:41):

and somehow that made me feel a bit better

view this post on Zulip Daniel Keys (Mar 21 2020 at 18:42):

It is interesting to see how these very simple textbook problems (in this case, I was trying to prove a positive real number has a floor and a ceiling in the naturals) lead to such discussions and insight.

view this post on Zulip Marc Huisinga (Mar 21 2020 at 18:44):

Patrick Stevens said:

Fair enough, though I weep to hear that things might simply have to be this way

it's a fun experiment to define something new and carry around some invariant together with data! i think that even something as simple as Maybe will quickly lead to headaches.
that being said, there are cases where the invariant is carefully maintained by the library, and you won't have to deal with the pain if what you want is in the library.
e.g. https://github.com/leanprover-community/mathlib/blob/master/src/data/finset.lean

view this post on Zulip Johan Commelin (Mar 21 2020 at 19:16):

@Patrick Stevens I know exactly how you feel. It's really quite crazy.

view this post on Zulip Johan Commelin (Mar 21 2020 at 19:18):

In the end it boils, I've come to realise that it boils down to a pragmatic usability argument.
And like Kevin said. Just imagine that there is a little dot written above almost every function that you see...

view this post on Zulip Johan Commelin (Mar 21 2020 at 19:18):

/, and ^-1 (inversion) and sqrt etc... they are all cheating on inputs where mathematicians would say they are undefined.

view this post on Zulip Patrick Stevens (Mar 21 2020 at 20:03):

I don't reeeallly mind the cheating - I have aesthetic objections, but really the thing I actually care about is "will this lead me to make mistakes", and I'm liable to make lots of mistakes if the types don't constrain me :P

view this post on Zulip Daniel Keys (Mar 21 2020 at 20:08):

Still having trouble even with int, shouldn't this goal follow from h6 below?

x : ,
m : ,
h6 : (m - 1)  x
 m - 1  x

Where can a type mismatch arise from here? Trying exact h6 I get:

invalid type ascription, term has type
  ↑(m - 1) ≤ x
but is expected to have type
  ↑m - 1 ≤ x

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 20:35):

The problem is that it's not exactly h6 :-)

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 20:36):

The order of the subtraction and the coercion are different, right? The brackets are in different places

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 20:37):

Just do convert h6. That will probably change the goal to the assertion that the coercion commutes with subtraction

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 20:37):

Then you can probably use norm_cast to finish the job

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 20:38):

Or perhaps norm_cast will change either the goal into the hypothesis or vice versa

view this post on Zulip Daniel Keys (Mar 21 2020 at 20:39):

It worked! I had tried some 20 other ways.

view this post on Zulip Johan Commelin (Mar 21 2020 at 21:21):

Patrick Stevens said:

I don't reeeallly mind the cheating - I have aesthetic objections, but really the thing I actually care about is "will this lead me to make mistakes", and I'm liable to make lots of mistakes if the types don't constrain me :P

Well, the first thing that you do after your definition, is prove a lemma that under the assumption that the input makes sense, the definition behaves the way it should. Once you've proven that lemma, you can't really make mistakes.

view this post on Zulip Patrick Massot (Mar 21 2020 at 21:22):

Even before that you cannot really make a mistake in a sense. As worse you can state and prove something which is not what you have in mind.

view this post on Zulip Johan Commelin (Mar 21 2020 at 21:23):

Well, that depends on what you mean with mistake...

view this post on Zulip Johan Commelin (Mar 21 2020 at 21:23):

lemma fermat_last_thm : true := trivial

is a mistake, in my book.

view this post on Zulip Patrick Massot (Mar 21 2020 at 21:24):

This is completely independent from our discussion

view this post on Zulip Patrick Massot (Mar 21 2020 at 21:25):

You can write:

import data.real.basic

example : (1 : )/0 = 0 := by simp

and call it a mistake or a misunderstanding of the statement, depending on your point of view.

view this post on Zulip Kevin Buzzard (Mar 21 2020 at 22:10):

example :  (n : ), 1 / n = 0 := 0, rfl

This is an example which every mathematician would say was false, but there's a proof.

view this post on Zulip Stephanie Zhou (Mar 22 2020 at 01:25):

Mario Carneiro said:

I don't think e has been defined, but you can use real.exp 1 if you import data.complex.exponential

I can't import either of those, as lean says "not found in the LEAN_PATH". Actually, I'm getting this issue for "import standard" and a lot of other common import statements. Would you know how to resolve this?

view this post on Zulip Mario Carneiro (Mar 22 2020 at 01:28):

import standard doesn't exist AFAIK, but if import data.complex.exponential doesn't work then you most likely don't have mathlib installed. Could someone with leanproject experience give setup advice here?

view this post on Zulip Kenny Lau (Mar 22 2020 at 01:28):

https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/Inequality.20World/near/190568509

view this post on Zulip Mario Carneiro (Mar 22 2020 at 01:30):

@Patrick Stevens By the way, there is a function called nat.psub : nat -> nat -> option nat that actually returns none when it's not supposed to be defined. You have to write funny monadic code if you want to compose it with other operations though.

view this post on Zulip Alex Mathers (Mar 22 2020 at 07:00):

I'm looking at the files defining submonoids, and I'm trying to understand some Lean notation. I see the following

instance has_mul : has_mul S := λ a b, a.1 * b.1, S.mul_mem a.2 b.2⟩⟩

and I'm trying to understand what the a.1 and a.2 mean. When I try to evaluate to see what these mean here is what I see:

variables (S : submonoid M) (a : S)
#check a     --- a : ↥S
#check a.1     --- a.val : M
#check a.2     --- a.property : (λ (x : M), x ∈ has_coe_t_aux.coe (set M) S) (a.val)

so I take it it has to do with the coercion from S to M. But what is really happening here?

view this post on Zulip Mario Carneiro (Mar 22 2020 at 07:03):

a has type ↥S, which is actually {x : M // x \in S}. So a is a pair of an element of M and a proof that that element is in S

view this post on Zulip Mario Carneiro (Mar 22 2020 at 07:05):

You can also write \u a instead of a.1 to produce the element of M

view this post on Zulip Mario Carneiro (Mar 22 2020 at 07:05):

or just a, since the coercion is implicitly inserted

view this post on Zulip Alex Mathers (Mar 22 2020 at 07:05):

I see! Thanks.

view this post on Zulip Mario Carneiro (Mar 22 2020 at 07:05):

the idea with all the notations is to try to make this act as much like a subset as possible

view this post on Zulip Daniel Keys (Mar 22 2020 at 21:28):

Does anyone know a short way to obtain a contradiction here, or should I dig further into where uniqueness of the supremum, lub, resides?

D : is_lub A 3,
E : is_lub A 0
 false

view this post on Zulip Daniel Keys (Mar 22 2020 at 21:30):

Oh, I got it. It is in the same file, bounds.lean. Can easily use eq_of_is_lub_of_is_lub.

view this post on Zulip Kevin Buzzard (Mar 22 2020 at 21:30):

It looks to me like it would be worth proving the lemma that if A has two least upper bounds then they are equal, or (if your definition of is_lub is from the library and not home-rolled) using the result in mathlib (assuming it's there, which it surely will be). If you're using mathlib's is_lub (assuming it has one) then just take a look at the 100 lines of code after the definition.

view this post on Zulip Kevin Buzzard (Mar 22 2020 at 21:31):

The rule is: if it's a standard result about a definition in the library, then it's proved in the library, probably not too far after the definition.

view this post on Zulip Stephanie Zhou (Mar 23 2020 at 18:07):

Does lean support trig functions and power series?

view this post on Zulip Johan Commelin (Mar 23 2020 at 18:09):

Trig functions: yes. Power series: to some extent.

view this post on Zulip Patrick Massot (Mar 23 2020 at 18:11):

Note that the question is not quite right. Lean itself virtually supports any mathematics, and actually knows very little. Then formalizations written in Lean know some stuff. The big one is mathlib, which is meant to be the base for all other mathematics developments, and this is what Johan's answer refer to.

view this post on Zulip Stephanie Zhou (Mar 23 2020 at 18:16):

What is the command for sin and cos?

view this post on Zulip Patrick Massot (Mar 23 2020 at 18:17):

Do you have a working Lean project together with a compiled mathlib?

view this post on Zulip Stephanie Zhou (Mar 23 2020 at 18:18):

Yes

view this post on Zulip Patrick Massot (Mar 23 2020 at 18:19):

import analysis.complex.exponential
open complex
#check sin

view this post on Zulip Reed Mullanix (Mar 23 2020 at 18:47):

Hey all, stupid question: Does lean have some analog to agda's interactive holes?

view this post on Zulip Alex J. Best (Mar 23 2020 at 18:51):

I don't know agda, but from a quick google, it sounds like _ is the replacement of agda's ?, in that you can write terms with _ to see what the type of _ should be and then fill it in.

view this post on Zulip Bryan Gin-ge Chen (Mar 23 2020 at 18:51):

Lean does support "hole commands" but they're not as easy to use as Agda's. I don't think we have anything like Agda's Auto, for instance. (**Edit: on second thought library_search is kind of like Auto.)

view this post on Zulip Reed Mullanix (Mar 23 2020 at 18:52):

Hmm, I tried that, and it looks like the typechecker got stuck

 types.lean    42  95 error           type mismatch, term
   congr_fun ?m_5 ?m_6
 has type
   ?m_3 ?m_2 = ?m_4 ?m_2
 but is expected to have type
   σ.app Y (F.map f x) = G.map f (σ.app X x) (lean-checker)

view this post on Zulip Alex J. Best (Mar 23 2020 at 18:52):

What were you trying to do?

view this post on Zulip Reed Mullanix (Mar 23 2020 at 18:54):

I'm just messing around with some existing proofs to try to get a better feel on how to use the system :)

For context, the proof in question is

lemma naturality (f : X ⟶ Y) (x : F.obj X) : σ.app Y ((F.map f) x) = (G.map f) (σ.app X x) := congr_fun _ _

From mathlib's category_theory/types.lean

view this post on Zulip Alex J. Best (Mar 23 2020 at 18:59):

I guess there are too many implicit things in that example, if you just write
lemma naturality (f : X ⟶ Y) (x : F.obj X) : σ.app Y ((F.map f) x) = (G.map f) (σ.app X x) := congr_fun _ x
you get to see what the type of _ should be

view this post on Zulip Reed Mullanix (Mar 23 2020 at 19:01):

Yeah, it barfs about not being able to synthesize a placeholder context, which isn't _super_ suprising, it's a pretty gnarly unification problem

view this post on Zulip Kevin Buzzard (Mar 23 2020 at 20:19):

If you write @f instead of f you can fill in some of the unification holes yourself

view this post on Zulip Reed Mullanix (Mar 23 2020 at 22:53):

More silly questions: I'm trying to use the rewrite tactic, and it's complaining that it can't find an instance of the pattern, even though there obviously is one:

 braided.lean    45   3 error           rewrite tactic failed, did not find instance of the pattern in the target expression
   (λ_ (X ⊗ 𝟙_ C)).hom ≫ (braid X (𝟙_ C)).hom
 state:
 C : Type u,
 _inst_1 : category C,
 _inst_2 : monoidal_category C,
 𝒞 : braided_category C,
 X : C
 ⊢ (((braid X (𝟙_ C)).hom ⊗ 𝟙 (𝟙_ C)) ≫ (α_ (𝟙_ C) X (𝟙_ C)).hom ≫ (λ_ (X ⊗ 𝟙_ C)).hom) ≫
       (braid X (𝟙_ C)).hom =
     ((ρ_ X).hom ⊗ 𝟙 (𝟙_ C)) ≫ (braid X (𝟙_ C)).hom (lean-checker)

view this post on Zulip Alex J. Best (Mar 23 2020 at 22:54):

Can you post full code? A minimal working example

view this post on Zulip Reed Mullanix (Mar 23 2020 at 22:55):

Of course! This is what I've got so far:

import category_theory.monoidal.category
import category_theory.natural_isomorphism

open category_theory

universes v u

namespace category_theory


class braided_category (C : Type u) [category.{v} C] [𝒞 : monoidal_category.{v} C] :=
(braid : Π X Y : C, (X ⊗ Y) ≅ (Y ⊗ X))
(braid_naturality' :
  ∀ {X₁ X₂ Y₁ Y₂} (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂),
  (f₁ ⊗ f₂) ≫ (braid Y₁ Y₂).hom = (braid X₁ X₂).hom ≫ (f₂ ⊗ f₁) . obviously)
-- first hexagon identity:
(hexagon' : ∀ X Y Z : C,
  (α_ X Y Z).hom ≫ (braid X (Y ⊗ Z)).hom ≫ (α_ Y Z X).hom
  = ((braid X Y).hom ⊗ (𝟙 Z)) ≫ (α_ Y X Z).hom ≫ ((𝟙 Y) ⊗ (braid X Z).hom) . obviously)
-- second hexagon identity:
(hexagon_inv' : ∀ X Y Z : C,
  (α_ X Y Z).inv ≫ (braid (X ⊗ Y) Z).hom ≫ (α_ Z X Y).inv
  = ((𝟙 X) ⊗ (braid Y Z).hom) ≫ (α_ X Z Y).inv ≫ ((braid X Z).hom ⊗ (𝟙 Y)) . obviously)

restate_axiom braided_category.braid_naturality'
restate_axiom braided_category.hexagon'
restate_axiom braided_category.hexagon_inv'

open monoidal_category
open braided_category

namespace braided_category

variables {C : Type u} [category.{v} C] [monoidal_category.{v} C] [𝒞 : braided_category.{v} C]
include 𝒞

section

lemma braid_coherence {X : C} :
  ((braid X (𝟙_ C)).hom ⊗ 𝟙 (𝟙_ C)) ≫ ((left_unitor X).hom ⊗ 𝟙 (𝟙_ C)) = ((right_unitor X).hom ⊗ 𝟙 (𝟙_ C)) :=
begin
  apply (cancel_mono (braid X (𝟙_ C)).hom).1,
  rw [←left_unitor_tensor, ←left_unitor_naturality C (braid X (𝟙_ C)).hom],
  sorry
end

end

end braided_category

end category_theory

view this post on Zulip Reed Mullanix (Mar 23 2020 at 22:58):

I suspect that it may have something to do with associativity actually, missed a pair of parens :face_palm:

view this post on Zulip Alex J. Best (Mar 23 2020 at 23:00):

Ah okay, does that fix it then?

view this post on Zulip Alex J. Best (Mar 23 2020 at 23:01):

In general if rw is having trouble you can use simp only [your_eq] or use conv to isolate the part you want to rewrite.

view this post on Zulip Reed Mullanix (Mar 23 2020 at 23:02):

Mucking about to figure out how to get assoc into scope, but I suspect that will do it. Thanks for the help :slight_smile:

view this post on Zulip Kevin Buzzard (Mar 23 2020 at 23:14):

\gg is right associative:

import category_theory.functor

#print notation 
-- _ `≫`:80 _:79 := category_theory.category_struct.comp #1 #0

80>79

view this post on Zulip Kevin Buzzard (Mar 23 2020 at 23:15):

@Reed Mullanix if you post code with ```lean at the top then you get syntax highlighting.

view this post on Zulip Alex Mathers (Mar 25 2020 at 01:14):

How are powers of elements (say elements in a monoid or group) defined in Lean? In this file (https://github.com/leanprover-community/mathlib/blob/master/src/group_theory/submonoid.lean) where submonoids are defined, they use expressions like x^n but searching around I don't see where this notation is first implemented. When I try to type it into Lean myself it looks like it's notation for has_pow M ℕ, so were monoids at some point endowed with this has_pow attribute and I just don't see where?

view this post on Zulip Shing Tak Lam (Mar 25 2020 at 01:17):

https://github.com/leanprover-community/mathlib/blob/24b82c91583843597e8cfeb7928d446dec776456/src/algebra/group_power.lean#L20

(the docs link below is probably better)

view this post on Zulip Alex J. Best (Mar 25 2020 at 01:18):

https://leanprover-community.github.io/mathlib_docs/algebra/group_power.html#monoid.has_pow

view this post on Zulip Alex J. Best (Mar 25 2020 at 01:18):

Too quick for me ;)

view this post on Zulip Shing Tak Lam (Mar 25 2020 at 01:19):

I just Ctrl-P monoid.pow and I had mathlib open on GitHub already :) The docs link is probably the better one though.

view this post on Zulip Alex Mathers (Mar 25 2020 at 01:21):

Not sure how I missed that there's an entire file titled group_power! Thanks

view this post on Zulip Shing Tak Lam (Mar 25 2020 at 01:21):

Are you on VSCode?

view this post on Zulip Alex J. Best (Mar 25 2020 at 01:22):

Yeah I just run a search in vscode for instance.*monoid.*has_pow

view this post on Zulip Alex Mathers (Mar 25 2020 at 01:32):

I am on VSCode, I had no idea I could do that

view this post on Zulip Shing Tak Lam (Mar 25 2020 at 01:34):

Or you can just press Ctrl-P then type in # in the search bar. It searches for whatever comes after the # in mathlib. So I just searched for monoid.pow. You could have also (probably a better idea) searched for monoid.has_pow.

view this post on Zulip Alex Mathers (Mar 25 2020 at 01:37):

This is definitely good information I was lacking. Thank you both!

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 05:11):

Hey all, I screwed up the basic install on fedora and lean in VSCODE says file topology/basic not found in teh LEAN_PATH

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 05:11):

Any help?

view this post on Zulip Yury G. Kudryashov (Mar 25 2020 at 05:14):

Which instructions did you follow? Are you editing a file in mathlib, or using it as a dependency?

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 05:34):

@Yury G. Kudryashov I tried the pip3 install mathlibtools for installing the leanproject, but it didn't seem to install.
I can use lean and leanpkg just fine, they've been updated to 3.7 no problem.

view this post on Zulip Bryan Gin-ge Chen (Mar 25 2020 at 07:09):

Not sure if this is the problem, since you haven't answered Yury's second question, but note that you should not open a single Lean file in VS Code, you need to open a directory containing a Lean project. Check the instructions here if you haven't already.

view this post on Zulip Patrick Massot (Mar 25 2020 at 16:26):

Miguel Raz Guzmán Macedo said:

I tried the pip3 install mathlibtools for installing the leanproject, but it didn't seem to install.

There is no way anyone could help you based on such vague information.

view this post on Zulip Johan Commelin (Mar 25 2020 at 16:32):

@Miguel Raz Guzmán Macedo As user or as root? Maybe prepend sudo or use pip3 install --user.

view this post on Zulip Patrick Massot (Mar 25 2020 at 16:43):

Johan, you are trying to guess too much. Maybe install worked but leanproject is not in the PATH. We can't know without further information;

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:43):

Thanks for the replies !
@Johan Commelin I tried both already. I found leanproject.py in my /usr/local/lib/python3.7/site-packages-mathlibtools/leanproject.py, but the Installation instructions didn't say anything about adding that manually to the path, so lemme try that.

view this post on Zulip Patrick Massot (Mar 25 2020 at 17:44):

You should not add that to your path

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 17:45):

We are still keen to see the error message.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 17:46):

and your answer to Yury's second question.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:48):

I am not trying to edit a file in mathlib, I am just trying to run the tutorial here (the topological_space check)

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:49):

Thank you all for your time and patience by the way, it means a lot to help on-ramping beginners :+1:

view this post on Zulip Patrick Massot (Mar 25 2020 at 17:49):

How did you create a project?

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:49):

@Johan Commelin if I run sudo pip3 install mathlibtools, it says all of the requirements for all the packages are satisfied.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:50):

@Patrick Massot I had used leanpkg instead of leanproject, I am trying to use leanproject now.

view this post on Zulip Patrick Massot (Mar 25 2020 at 17:51):

Can you run leanproject now? (without adding weird things to your path)

view this post on Zulip Mario Carneiro (Mar 25 2020 at 17:51):

Hey, now that we have control over lean, we should REALLY remove that misleading error message that says "add this to your LEAN_PATH"

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:52):

Patrick Massot said:

Can you run leanproject now? (without adding weird things to your path)

No, in a new terminal leanproject does says
fish: leanproject command not found

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:54):

I am guessing leanproject should have been installed when I did sudo pip3 install mathlibtools?

view this post on Zulip Patrick Massot (Mar 25 2020 at 17:56):

Yes, it should be in /usr/local/bin/leanproject (at least assuming a Debian-like OS)

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 17:58):

Sorry, there's no leanproject there :(

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:00):

If I try to do pip3 install --user mathlibtools I get this error at the end -

PermissionError: [Errno 13] Permission denied: '/usr/local/lib64/python3.7/site-packages/wrapt-1.12.1-py3.7.egg-info'

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:01):

And it is entirely possible I may have bungled up my entire environment, so suggestions are welcome.

view this post on Zulip Patrick Massot (Mar 25 2020 at 18:01):

It very much looks like your python environment is destroyed. What is your OS/distrib?

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:01):

fedora latest.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:06):

I tried to chmod -R au+x ..../site-packages/ and now I get
Permission denied: '/usr/local/lib/python3.7/site-packages/tqdm-4.43.0.dist-info'

view this post on Zulip Patrick Massot (Mar 25 2020 at 18:10):

You shouldn't randomly change permissions in /usr/local

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:10):

Oh.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:11):

:S

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:15):

Well now pip3 install --user mathlibtools works, and all requirements are already satisfied :D

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:41):

Aha, it seems I needed to add ~/.local/bin to path, uninstalling and installing seems to have suggested that and leanproject new leanjl now works. Thank you all for the help on that.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:44):

Well, import topology.basic still says file 'init' not found in the LEAN_PATH

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:45):

test.lean:1:0: error
file 'init' not found in the LEAN_PATH
test.lean:1:0: error
invalid import: init
could not resolve import: init
test.lean:1:0: error
invalid import: topology.basic
/home/mrg/deps/lean/mathlib/src/topology/basic.lean:48:25: error: unexpected token

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 18:54):

So now you need to answer the question about whether you opened the project directory with the Open Folder command, or just a random file.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:55):

Ah, sorry.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 18:56):

You need to open the root directory of the project in VS code. You're nearly there

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:56):

I did leanproject new leanjl to start a new project, opened it with VSCode via code leanjl, and added a file in src

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:56):

just called test.lean.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 18:59):

and that's where I put the

import topology.basic

#check topological_space

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:26):

I can't reproduce. I just did exactly that and I get topological_space : Type u_1 → Type u_1

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:27):

leanjl.png

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:29):

VS Code View -> Terminal followed by lean --version gives me Lean (version 3.7.2, commit 44fb9f994d0f, Release) . My leanpkg.path is

builtin_path
path _target/deps/mathlib/src
path ./src

and my leanpkg.toml is

[package]
name = "leanjl"
version = "0.1"
lean_version = "leanprover-community/lean:3.7.2"
path = "src"

[dependencies]
mathlib = {git = "https://github.com/leanprover-community/mathlib", rev = "24b82c91583843597e8cfeb7928d446dec776456"}

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:39):

Thanks a lot for the follow - through @Kevin Buzzard .
I get the exact same configs down to the hashes for lean 3.7.2 and mathlib and both files are identical.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:43):

cool

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:44):

you beat the system

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:45):

If I had a penny...

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:48):

Are you absolutely sure that your VS Code looks exactly the same as my screenshot?

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:48):

VSCode is maybe picking up a previous install of lean:
I get this error there as well:

invalid import: topology.basic
/home/mrg/deps/lean/mathlib/src/topology/basic.lean:48:25: error: unexpected token

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:49):

That is definitely not the mathlib you are looking for

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:50):

imma nuke it brb.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:50):

the mathlib you're supposed to be using is in _target in your project folder

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:51):

If you had posted that error much earlier then life would have been a bit easier. Can you post all the details of every error which you are currently experiencing?

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:51):

Exit VS Code and start it again and post all errors which occur anywhere.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:52):

Miguel Raz Guzmán Macedo said:

test.lean:1:0: error
file 'init' not found in the LEAN_PATH
test.lean:1:0: error
invalid import: init
could not resolve import: init
test.lean:1:0: error
invalid import: topology.basic
/home/mrg/deps/lean/mathlib/src/topology/basic.lean:48:25: error: unexpected token

I did post it earler - I should have read more closely.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:52):

Where are you seeing this error?

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:53):

Do you have a LEAN_PATH variable set? If so, nuke it.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:53):

unset LEAN_PATH

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:54):

then restart VS Code and see if the error has changed

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:54):

(from the same terminal where you nuked LEAN_PATH)

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:55):

DING DING DING

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:55):

I had monkey-patched an earlier version of LEAN_PATH in my configs and it was polluting the env.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:55):

I now get a very happy topological_space : Type u_1 → Type u_1

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:56):

That's great to know. That one was a real toughie. LEAN_PATH was something which you had to worry about in 2018.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:56):

Huh, yeah, I think that was my first install attempt or so.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:57):

So it will be rare that users run into this problem but perhaps not impossible. Assuming you rebooted your computer in the past few years you might want to try and figure out what is setting LEAN_PATH.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:57):

(unless you were setting it yourself)

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:57):

Thank you all a lot @Johan Commelin @Patrick Massot and @Kevin Buzzard , that was very attentive of all of you.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:57):

The perfectoid project team -- installing mathlib on a computer near you.

view this post on Zulip Miguel Raz Guzmán Macedo (Mar 25 2020 at 19:58):

Kevin Buzzard said:

So it will be rare that users run into this problem but perhaps not impossible. Assuming you rebooted your computer in the past few years you might want to try and figure out what is setting LEAN_PATH.

Nope, all me and my footguns.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 19:59):

Wherever did you read about LEAN_PATH? We should nuke the reference

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 20:00):

By the way I think you just accidentally created a new stream. Usually we talk in threads in the streams we already have.

view this post on Zulip Bryan Gin-ge Chen (Mar 25 2020 at 20:48):

Wherever did you read about LEAN_PATH?

Whenever Lean is unable to find an imported file, it says "error: file 'does/not/exist' not found in the LEAN_PATH". People might read this and think they need to set LEAN_PATH, when that's rarely the right thing to do.

view this post on Zulip Bryan Gin-ge Chen (Mar 25 2020 at 20:49):

It wouldn't be hard to change the message. Any suggestions?

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 20:55):

"error: file 'does/not/exist' not found" would already be strictly better, given what we just went through.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 20:56):

The moment you mention leanpkg.path we'll have people changing that.

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 20:56):

which is also rarely the right thing to do.

view this post on Zulip Mario Carneiro (Mar 25 2020 at 20:56):

How about "lean file does.not.exist not found. We searched: <print result of lean --path>"

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 20:57):

Now that might even be a helpful message!

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 20:57):

Actually on looking at the output

{
  "is_user_leanpkg_path": true,
  "leanpkg_path_file": "/home/buzzard/.lean/leanpkg.path",
  "path": [
    "/home/buzzard/.elan/toolchains/stable/bin/../library",
    "/home/buzzard/.elan/toolchains/stable/bin/../lib/lean/library"
  ]
}

I am suddenly less sure.

view this post on Zulip Mario Carneiro (Mar 25 2020 at 20:58):

Well, lean --path is json formatted for no good reason

view this post on Zulip Mario Carneiro (Mar 25 2020 at 20:58):

we can print the same info in a more human readable way

view this post on Zulip Mario Carneiro (Mar 25 2020 at 21:00):

It might be sufficient to just focus on (1) whether a leanpkg.path file could be found, and (2) what the location and contents of the path file are

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 21:00):

{
  "is_user_leanpkg_path": false,
  "leanpkg_path_file": "/home/buzzard/lean-projects/lean-perfectoid-spaces/leanpkg.path",
  "path": [
    "/home/buzzard/.elan/toolchains/leanprover-community-lean-3.5.1/bin/../library",
    "/home/buzzard/.elan/toolchains/leanprover-community-lean-3.5.1/bin/../lib/lean/library",
    "/home/buzzard/lean-projects/lean-perfectoid-spaces/_target/deps/mathlib/src",
    "/home/buzzard/lean-projects/lean-perfectoid-spaces/./src"
  ]
}

Here's a more accurate representation (I ran lean --path in a project). I still think it's a risk mentioning leanpkg.path but perhaps that vector of paths is something worth printing out?

view this post on Zulip Mario Carneiro (Mar 25 2020 at 21:01):

the idea here is to get the low level information about where lean is looking

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 21:01):

why is it not a user leanpkg path?

view this post on Zulip Mario Carneiro (Mar 25 2020 at 21:01):

we can also include more suggestive comments about checking their toml file and so on

view this post on Zulip Kevin Buzzard (Mar 25 2020 at 21:01):

When I tried not in a project I got is_user_leanpkg_path true and in a project I get that it's false?

view this post on Zulip Mario Carneiro (Mar 25 2020 at 21:02):

I think is_user_leanpkg_path means it is using the global leanpkg.path file in your home directory

view this post on Zulip Bryan Gin-ge Chen (Mar 25 2020 at 22:37):

One wrinkle is that Lean currently spits out a separate message for each file it can't find, so we may need to change the error handling somehow so that we don't repeat the same helpful message over and over.

view this post on Zulip Stephanie Zhou (Mar 26 2020 at 01:19):

How does one use imaginary numbers in lean?

view this post on Zulip Yury G. Kudryashov (Mar 26 2020 at 03:07):

Complex numbers are defined in data.complex. What do you want to prove about them?

view this post on Zulip Alex Mathers (Mar 26 2020 at 08:10):

Can anybody tell me the problem with some code? for the purposes of practicing some things I have defined subgroups in the "bundled" way and am trying to define the intersection of a family of subgroups (really just the underlying set at this point) but I'm getting a lot of unexpected error messages. My code looks like this

def Inf {ι : Type*} (s : ι  subgrp G) : subgrp G :=
{carrier := ( i, s i),
mult_mem' := sorry,
inv_mem' := sorry
}

and the error messages that come up are:

grps.lean:221:15: error
unknown identifier 'i'
grps.lean:221:16: error
invalid expression, `)` expected
grps.lean:221:20: error
invalid structure instance, ':=' expected
grps.lean:221:21: error
invalid structure instance, '}' expected
grps.lean:221:21: error
command expected

edit: also as some extra comments, I'm basing the omission of any kind of explicit i \in \io off of what I've seen in mathlib, and adding it doesn't seem to change anything. And I have the coercion set up so that Lean understands it is really taking the intersection of the underlying "carrier" sets, so I don't think the issue is there.

view this post on Zulip Mario Carneiro (Mar 26 2020 at 08:21):

I think you have the wrong intersection symbol

view this post on Zulip Johan Commelin (Mar 26 2020 at 08:21):

Try \bigcap

view this post on Zulip Alex Mathers (Mar 26 2020 at 08:23):

That fixed it. So is \cap for two things and \bigcap for arbitrary intersections?

view this post on Zulip Stephanie Zhou (Mar 26 2020 at 13:11):

Yury G. Kudryashov said:

Complex numbers are defined in data.complex. What do you want to prove about them?

I'm trying to prove Euler's formula using polar coordinates, so I wanted to use i.

view this post on Zulip Johan Commelin (Mar 26 2020 at 13:12):

Have you found it?

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:12):

Is that theorem already in Lean? You should check the docs.

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:12):

https://leanprover-community.github.io/mathlib_docs/

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:16):

I found it -- it's here

 theorem complex.exp_mul_I (x : ℂ) :
(x * complex.I).exp = x.cos + x.sin * complex.I

I can live with complex.I but do we really want x.cos rather than cos(x)\cos(x) in the docs? Can we have maths mode docs?

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:16):

@Patrick Massot how does that work?

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:17):

And where does the Wikipedia link to Euler's formula fit into the docs?

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:17):

@Rob Lewis ?

view this post on Zulip Mario Carneiro (Mar 26 2020 at 13:19):

presumably on the relevant formula...?

view this post on Zulip Mario Carneiro (Mar 26 2020 at 13:20):

there is no rule saying you can't put doc strings on theorems, that's just systematic laziness on our part

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:23):

Can a docstring have a URL?

view this post on Zulip Rob Lewis (Mar 26 2020 at 13:24):

Sure, just put it in angle brackets. <www.kevin.com>

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:24):

I just want the docstring to say "<link>Euler's formula</link>. The statement that eiθ=cos(θ)+isin(θ)e^{i\theta}=\cos(\theta)+i\sin(\theta)"

view this post on Zulip Rob Lewis (Mar 26 2020 at 13:25):

Or [Euler's formula](www.kevin.com)

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:25):

Can we get the docs to display maths mode somehow?

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:25):

I want @Stephanie Zhou to solve her problem herself by just going to the docs and typing "Euler's formula" into the search box.

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:26):

Note that there are about ten Euler's formulas.

view this post on Zulip Rob Lewis (Mar 26 2020 at 13:26):

They do, you asked for this a while back. $...$ inline, $$...$$ block, but there are potential bad interactions with markdown so don't put anything in math mode that's also valid markdown.

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:28):

But then I think @Sebastien Gouezel complained that he didn't want to see $ signs cluttering up his docstrings when one could just as easily write eⁱᶿ = cos(θ) + i sin (θ) in unicode.

view this post on Zulip Kevin Buzzard (Mar 26 2020 at 13:29):

and I just look at that rendering and think "OMG it's Microsoft Word all over again"

view this post on Zulip David Wärn (Mar 28 2020 at 14:54):

example (α : Type) [nonempty α] (f : α  ) :  a,  b, f a  f b := sorry

Does this theorem have a name? library_search didn't succeed

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 14:56):

I guess you can prove it with nat.find but I don't know the name.

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 14:57):

there's probably a one-liner with some clever application of a well-ordering principle

view this post on Zulip David Wärn (Mar 28 2020 at 15:02):

Yes, it follows from well-foundedness of f a < f b and the fact that a nonempty well-founded type has a minimal element. But I also couldn't find this latter fact...

view this post on Zulip David Wärn (Mar 28 2020 at 15:03):

I guess that's "find" for general well-orders

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 15:20):

Maybe this and nearby stuff in order.basic are useful?

view this post on Zulip Kenny Lau (Mar 28 2020 at 15:30):

what on earth is this mode? I keep learning new stuff about github

view this post on Zulip Kenny Lau (Mar 28 2020 at 15:34):

import order.complete_lattice

#check (by apply_instance : lattice.has_Inf )

view this post on Zulip Kenny Lau (Mar 28 2020 at 15:34):

why is there no such instance

view this post on Zulip Kenny Lau (Mar 28 2020 at 15:34):

oh because it doesn't have a top element

view this post on Zulip Kenny Lau (Mar 28 2020 at 15:34):

lattice is confusing

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 15:37):

It's probably a semilattice_sup_bot or something

view this post on Zulip David Wärn (Mar 28 2020 at 15:38):

example (α : Type) [nonempty α] (f : α  ) :  a,  b, f a  f b := begin
  have : well_founded (λ a b, f a < f b), from measure_wf _,
  set h := well_founded.has_min this set.univ set.univ_nonempty,
  simpa using h,
end

This seems to work

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 15:38):

ooh they're not going to like that non-terminal simp

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 15:38):

Can you use simpa somehow?

view this post on Zulip David Wärn (Mar 28 2020 at 15:40):

Better now?

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 15:40):

example (α : Type) [nonempty α] (f : α  ) :  a,  b, f a  f b := begin
  have : well_founded (λ a b, f a < f b), from measure_wf _,
  simpa using well_founded.has_min this set.univ set.univ_nonempty,
end

view this post on Zulip Kevin Buzzard (Mar 28 2020 at 15:40):

you beat me to it :-)

view this post on Zulip Alex Mathers (Mar 30 2020 at 05:44):

Is there any difference in practice between the following:

class unique_factorization_domain (α : Type*) [integral_domain α] :=
(factors : α  ... )
(factors_prod : ... )
(prime_factors : ... )

and

class unique_factorization_domain (α : Type*) extends integral_domain α :=
(factors : α  ... )
(factors_prod : ... )
(prime_factors : ... )

Just curious because I saw the former in a mathlib file whereas I'm used to seeing things like the latter

view this post on Zulip Mario Carneiro (Mar 30 2020 at 06:08):

Yes; while they basically perform the same function, there are a number of issues that come into play regarding which is better, mostly to do with how type class inference works

view this post on Zulip Mario Carneiro (Mar 30 2020 at 06:09):

The advice I usually give is to use extends unless the number of type arguments goes up (as in module which has two type arguments)

view this post on Zulip Alex Mathers (Mar 30 2020 at 06:17):

Perfect, I'll blindly stick to this then

view this post on Zulip Alex Mathers (Mar 31 2020 at 02:24):

what's this mean? or more importantly I guess, how do I "increase the setting option" as described?

maximum class-instance resolution depth has been reached (the limit can be increased by setting option 'class.instance_max_depth') (the class-instance resolution trace can be visualized by setting option 'trace.class_instances')

view this post on Zulip Bryan Gin-ge Chen (Mar 31 2020 at 02:25):

e.g. set_option class.instance_max_depth 100

view this post on Zulip Alex Mathers (Mar 31 2020 at 02:26):

Sweet. Should I be concerned or is this a normal adjustment to have to make?

view this post on Zulip Bryan Gin-ge Chen (Mar 31 2020 at 02:27):

It depends. If you share your code, we can make suggestions.

view this post on Zulip Kevin Buzzard (Mar 31 2020 at 07:18):

In my experience, the bug sometimes means "you have asked the type class inference system to do something super-complicated, which can be fixed with the set_option suggestion above" or "you have accidentally asked the type class inference system to do something impossible, your code is wrong and this error is a super-unhelpful way of informing you of this". Earlier you were getting errors about Lean not being able to find instances; this one might mean "you asked me to find an instance which is hard or impossible to find and I'm just getting confused".

view this post on Zulip Reid Barton (Mar 31 2020 at 15:04):

Yes, this is probably the second least predictive error message, after (deterministic) timeout

view this post on Zulip Miroslav Olšák (Apr 01 2020 at 09:00):

I wanted to add some shows to my code, and I am getting an error. Why is the show tactic failing in the following example? I thought it should succeed when I just copy the goal.

example (l : list ) : l.sum  0 :=
begin
  induction l,
  show list.sum list.nil  0,
  sorry, sorry,
end

view this post on Zulip Johan Commelin (Apr 01 2020 at 09:01):

It doesn't know what type of lists you want

view this post on Zulip Johan Commelin (Apr 01 2020 at 09:02):

Try show list.sum (list.nil : list int) ≥ 0

view this post on Zulip Johan Commelin (Apr 01 2020 at 09:02):

In fact, it will see the 0 at the RHS, and by default assume that this is (0 : nat)

view this post on Zulip Johan Commelin (Apr 01 2020 at 09:02):

Unless you already convinced it that you were talking about a different type.

view this post on Zulip Miroslav Olšák (Apr 01 2020 at 09:38):

Ah, the integers, thanks. show [].sum ≥ (0:ℤ) is working.

view this post on Zulip Shing Tak Lam (Apr 05 2020 at 13:55):

Is there a tactic that would solve goals like this? I tried hint, but that suggested ring, which didn't simplify things much (or at all).

(2 ^ 2 ^ succ n + 1) * (2 ^ 2 ^ succ n - 1) = 2 ^ 2 ^ succ (succ n) - 1

view this post on Zulip Patrick Massot (Apr 05 2020 at 13:59):

try ring_exp

view this post on Zulip Kevin Buzzard (Apr 05 2020 at 14:00):

Oh it's bloody nat subtraction again

view this post on Zulip Kevin Buzzard (Apr 05 2020 at 14:00):

example (n : ) :

(2 ^ 2 ^ succ n + 1) * (2 ^ 2 ^ succ n - 1) = 2 ^ 2 ^ succ (succ n) - 1 :=
begin
  repeat {rw nat.pow_succ},
  repeat {rw nat.pow_mul},
  generalize : 2 ^ 2 ^ n = t,
  -- ⊢ (t ^ 2 + 1) * (t ^ 2 - 1) = (t ^ 2) ^ 2 - 1
  ring, -- fails

view this post on Zulip Kevin Buzzard (Apr 05 2020 at 14:04):

import tactic

open nat

example (n : ) :
  (2 ^ 2 ^ succ n + 1) * (2 ^ 2 ^ succ n - 1) = 2 ^ 2 ^ succ (succ n) - 1 :=
begin
  repeat {rw nat.pow_succ},
  repeat {rw nat.pow_mul},
  generalize : (2 ^ 2 ^ n) ^ 2= t,
  cases t, refl,
  rw [succ_eq_add_one, nat.add_sub_cancel],
  ring,
end

@Shing Tak Lam the problem with a tactic is that you need to somehow insert the assertion that the subtraction doesn't give a junk answer. omega is good at this with very simple goals but this might be hard in general.

view this post on Zulip Kevin Buzzard (Apr 05 2020 at 14:06):

import tactic

open nat

example (n : ) :
  ((2 : ) ^ 2 ^ succ n + 1) * (2 ^ 2 ^ succ n - 1) = 2 ^ 2 ^ succ (succ n) - 1 :=
begin
  repeat {rw nat.pow_succ},
  repeat {rw pow_mul},
  ring,
end

Note the coercion in the statement: it's now a theorem about integers.

view this post on Zulip Shing Tak Lam (Apr 05 2020 at 14:22):

Kevin Buzzard said:

Oh it's bloody nat subtraction again

I know... Seems like everything I formalise I come across nat subtraction... Anyways, at least for this part (yes it's another random STEP question that I've come across), I think it's the same if I do it in the nats versus the ints, so I guess I can just change it to int. Although I might need data.nat.prime later on, so there may be issues if I switch.

I guess 2 ^ 2 ^ succ n > 1 is something that is obvious to me, but not obvious to lean.

view this post on Zulip Kevin Buzzard (Apr 05 2020 at 15:14):

It's not hard to prove, maybe even the monotonicity tactic will prove 2^2^(succ n)>2^2^0 or something

view this post on Zulip Asger Hautop Drewsen (Apr 06 2020 at 12:35):

At least in the "Natural number game" the "ring" tactic doesn't seem to be able to prove that

succ (a + b) = succ a + b

for a b : mynat.

Why is this?

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 12:37):

ring will only work once it knows that the structure is a semiring. Once it knows that, it will only work on terms which only involve functions which rings have, and succ isn't one of these. If Lean already knows the natural numbers are a semiring then you could rewrite succ_eq_add_one and it should work.

view this post on Zulip Kenny Lau (Apr 06 2020 at 12:37):

proposal to add succ_eq_add_one into ring

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 12:37):

what about mynat.succ_eq_add_one?

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 12:38):

because I suspect that's the one we're talking about here.

view this post on Zulip Kenny Lau (Apr 06 2020 at 12:38):

fair enough

view this post on Zulip Asger Hautop Drewsen (Apr 06 2020 at 12:38):

Ah, that makes sense, this works:

repeat {rw succ_eq_add_one}, ring,

view this post on Zulip Donald Sebastian Leung (Apr 06 2020 at 12:39):

Perhaps related: the omega tactic (a tactic specific to the natural numbers / integers, based on a fragment of Peano arithmetic called Presburger arithmetic) should be able to solve this. You probably won't be able to use it in the NNG, but in an actual Lean development, you can require it with import tactic (given that you have installed mathlib)

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 12:41):

I don't know if it's possible to make omega work on mynat. One should be able to give omega a term of type X \equiv+* nat and then it would work on X by magic :-)

view this post on Zulip Stephanie Zhou (Apr 06 2020 at 17:07):

How would I write out sin and cos as an infinite series? I can't seem to find infinite series in the docs

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 17:08):

Did you find the definition of sin?

view this post on Zulip Stephanie Zhou (Apr 06 2020 at 17:11):

Ah, this?
def sin (z : ℂ) : ℂ := ((exp (-z * I) - exp (z * I)) * I) / 2

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 17:11):

Right. And can you find the definition of exp?

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 17:12):

if you have mathlib open at sin then you might be able to right click on exp and jump to it.

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 17:14):

although having done this myself now, I see that you don't have to jump very far.

view this post on Zulip Stephanie Zhou (Apr 06 2020 at 17:48):

Okay, would I define sin and cos in this way at the beginning to get lean to rewrite this way?

view this post on Zulip Kevin Buzzard (Apr 06 2020 at 17:50):

I don't really understand the question. Mathlib has defined them that way, so if you want to use mathlib's sin and cos then you'll have to use their definitions. But exp is defined as a power series so you could mimic that if you wanted to define sin as a power series.

view this post on Zulip Brandon B (Apr 07 2020 at 03:23):

I'm trying to understand the difference between the theorem I wrote and the one that's in the Lean book to prove that, assuming p, one can prove p or q :

variables p q : Prop
theorem t1 (hp : p) : p  p  q := λ hp, or.intro_left q hp      --mine
theorem t2 (hp : p) : p  q := or.intro_left q hp      --in the book

I thought that a definition's (therefore theorem's) type should indicate the theorem to be proved, which should be "p -> p v q" not just "p v q" as in t2.

view this post on Zulip Donald Sebastian Leung (Apr 07 2020 at 03:29):

In t2, hp : p is already introduced as a hypothesis in the theorem statement so there's no need to add another p → in front of p ∨ q

view this post on Zulip Brandon B (Apr 07 2020 at 03:38):

I see, thanks

view this post on Zulip Lynn (Apr 07 2020 at 14:25):

Is there some way to check expressions inside a tactics block? I'd like to write something like

example (a b : Prop) : a ∨ b → b ∨ a :=
begin
  intro H,
  check H,
  ...

but this is not allowed (invalid tactic expression).

view this post on Zulip Johan Commelin (Apr 07 2020 at 14:26):

What would you like to happen?

view this post on Zulip Johan Commelin (Apr 07 2020 at 14:27):

If you use an editor like VScode, you can open the "Goal window" and it will show you the type of H

view this post on Zulip Patrick Massot (Apr 07 2020 at 14:28):

In this case Johan is right, but I think we still need a tactic doing that. This was discussed recently, did we do anything in the end?

view this post on Zulip Lynn (Apr 07 2020 at 14:29):

I would like to see H : a ∨ b printed to the console. It would be useful to insert check lines into some of the proofs in https://leanprover.github.io/tutorial so I can see what they're doing

view this post on Zulip Johan Commelin (Apr 07 2020 at 14:29):

The intended usage is that you open the tutorial in VScode

view this post on Zulip Patrick Massot (Apr 07 2020 at 14:30):

Arg, this is a very old tutorial!

view this post on Zulip Patrick Massot (Apr 07 2020 at 14:30):

This is not even Lean 3.

view this post on Zulip Patrick Massot (Apr 07 2020 at 14:31):

We really need to get rid of this trap.

view this post on Zulip Marc Huisinga (Apr 07 2020 at 14:31):

is it still linked somewhere or did you find it via google?

view this post on Zulip Johan Commelin (Apr 07 2020 at 14:31):

@Lynn Thanks for finding this! Please tell us how you found it, so that we can help the internet to unfind it.

view this post on Zulip Lynn (Apr 07 2020 at 14:32):

I suppose a clunky alternative is commenting out some suffix of the proof, to inspect the hypotheses and subgoals at that point.
I found it via Google (I probably looked for lean tutorial)

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:33):

If you have Lean installed using VS Code then all this information is available for you in a window.

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:34):

code.png

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:35):

The Lean 2 tutorial is the #1 hit on duckduckgo if you search for lean tutorial

view this post on Zulip Marc Huisinga (Apr 07 2020 at 14:35):

Kevin Buzzard said:

The Lean 2 tutorial is the #1 hit on duckduckgo if you search for lean tutorial

oh no

view this post on Zulip Alex J. Best (Apr 07 2020 at 14:35):

Yeah I just tried a number of variations on googling "lean tutorial" or just "lean prover" that page is listed very highly. Can we (@Gabriel Ebner ) move that git repo to "lean-2-tutorial" perhaps, or should we have something to replace it first?

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:36):

The Lean 2 links directly to a Lean 3 tutorial and there's also a warning

view this post on Zulip Rob Lewis (Apr 07 2020 at 14:36):

To be fair, the tutorial says about as explicitly as it can that it's out of date and links to the new one.

view this post on Zulip Lynn (Apr 07 2020 at 14:36):

I will try VS Code! I was enjoying the in-browser Lean environment, and the way it lets me play around without needing to install anything yet. Though I see https://leanprover.github.io/live offers the same functionality

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:36):

That's the old in-browser lean environment :-)

view this post on Zulip Patrick Massot (Apr 07 2020 at 14:37):

The Lean 3 tutorial it links too is also badly outdated, right?

view this post on Zulip Alex J. Best (Apr 07 2020 at 14:37):

Rob Lewis said:

To be fair, the tutorial says about as explicitly as it can that it's out of date and links to the new one.

Sure, but its still weird that the old tutorial is coming up so highly on search engines.

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:37):

leanprover is dead (actually, it's just resting), long live leanprover-community

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:37):

This version of the web editor has an up to date Lean and an up to date mathlib.

view this post on Zulip Lynn (Apr 07 2020 at 14:37):

My hasty reading of the warning:

Please note that this is the tutorial for Lean 2, which allows the use of homotopy type theory (HoTT). It is not the tutorial for the current version of Lean.

made me think the “current version of Lean” was _not yet_ Lean 2, and that this was an experimental tutorial for a new “Lean 2”. (It doesn't mention that the current version is Lean 3, rather than Lean 1.)

view this post on Zulip Johan Commelin (Apr 07 2020 at 14:38):

It would be really nice if leanprover.github.io would just show a message

Hi! We're really busy developing Lean 4.

In the mean time, please take a look at https://leanprover-community.github.io.

view this post on Zulip Johan Commelin (Apr 07 2020 at 14:39):

@Lynn Thanks! These bug reports are helpful! (We tend to gloss over them as more experienced users...)

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 14:39):

I don't see any reason why a newcomer would know whether the current version of Lean is Lean 2 or Lean 4 or whatever. Thanks for this observation Lynn.

view this post on Zulip Lynn (Apr 07 2020 at 14:39):

Specifying “which allows the use of homotopy type theory (HoTT)” sounds like the “current version of Lean” doesn't allow that, so Lean 2 must be surely more featureful, so the “current version” must be <2 :slight_smile:

view this post on Zulip Patrick Massot (Apr 07 2020 at 14:39):

Makes sense (when you don't know the story).

view this post on Zulip Marc Huisinga (Apr 07 2020 at 14:43):

i think the recommended ways to get into the current version of lean (lean 3) are either "theorem proving in lean" (https://leanprover.github.io/theorem_proving_in_lean/index.html) or kevin's natural number game (https://wwwf.imperial.ac.uk/~buzzard/xena/natural_number_game/).
theorem proving in lean (TPIL) explains things from first principles and (optionally) uses the in-browser lean environment. if you've got experience with functional programming, cs in general or other theorem provers, this might be up your alley, either as a reference or a tutorial, depending on how much you already know.
the natural number game (NNG) jumps right into proving things with tactics for natural numbers. people coming from mathematics seem to love it.

lastly, there's the new hitchhiker's guide to logical verification (https://github.com/blanchette/logical_verification_2020/raw/master/hitchhikers_guide.pdf), which i haven't read yet, but i'm sure it's great.

view this post on Zulip Lynn (Apr 07 2020 at 14:46):

I played through the “natural number game” a few months ago and really liked it :slight_smile: I should probably go through it again to jog my memory.

view this post on Zulip Ryan Lahfa (Apr 07 2020 at 16:08):

Patrick Massot said:

Makes sense (when you don't know the story).

I'm interested in the story for removing HoTT, it was not useful enough? Or too difficult to keep it in the Lean codebase?

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 16:10):

Leo just decided he wasn't going to support it. My guess is that he wasn't hearing any particular need to support it from the parts of the CS community which he listens to.

view this post on Zulip Kevin Buzzard (Apr 07 2020 at 16:11):

What I've learnt from the HoTT chat is there are still a lot of foundational questions which one has to answer after deciding to have some kind of univalence principle, and I'm not sure you can please all of the people all of the time.

view this post on Zulip Ryan Lahfa (Apr 07 2020 at 16:11):

Kevin Buzzard said:

What I've learnt from the HoTT chat is there are still a lot of foundational questions which one has to answer after deciding to have some kind of univalence principle, and I'm not sure you can please all of the people all of the time.

Makes sense

view this post on Zulip Michael J. Curry (Apr 07 2020 at 17:05):

I'm a machine learning person who's been hearing a lot about theorem provers recently (like many other people just started trying out the natural numbers game). I think it might be neat to see if it's possible to use Lean to prove some simple theorems that might be of interest in an ML setting. For example, Markov's inequality for random variables, or bounds on the range of a Lipschitz function. These seem very simple and like they might be fun to prove -- would it be possible? Or is Lean still mainly meant to be used for much more foundational stuff than that?

view this post on Zulip Ryan Lahfa (Apr 07 2020 at 17:06):

Michael J. Curry said:

I'm a machine learning person who's been hearing a lot about theorem provers recently (like many other people just started trying out the natural numbers game). I think it might be neat to see if it's possible to use Lean to prove some simple theorems that might be of interest in an ML setting. For example, Markov's inequality for random variables, or bounds on the range of a Lipschitz function. These seem very simple and like they might be fun to prove -- would it be possible? Or is Lean still mainly meant to be used for much more foundational stuff than that?

It's definitely possible to prove both of what you mentioned.
It is just that some stuff requires integrals / derivation which is currently being built in mathlib

view this post on Zulip Patrick Massot (Apr 07 2020 at 17:07):

@Koundinya Vajjha will tell you about https://arxiv.org/abs/1911.00385

view this post on Zulip Alex J. Best (Apr 07 2020 at 17:09):

There was also @Daniel Selsam et al.'s http://proceedings.mlr.press/v70/selsam17a/selsam17a.pdf

view this post on Zulip Andrew Ashworth (Apr 07 2020 at 17:14):

it is possible, if you have the correct background. For me, as an engineer, the difficulty is in getting to grips with the formal definitions of everything; measure-theoretic probability is not taught at all in the standard curriculum so you kind of have to teach yourself all the background material before can even state results that you take for granted

view this post on Zulip Michael J. Curry (Apr 07 2020 at 17:15):

thanks, those are both fantastic things to start looking at! the second paper in particular looks like it has some way of defining integrals and expectation operators that can be formally manipulated without actually having to worry about defining integration in a rigorous way.

view this post on Zulip Koundinya Vajjha (Apr 07 2020 at 20:38):

Markov's inequality and Chebyshev's Inequality were low hanging fruit since mathlib's measure theory library is very mature. So I proved those without too much hassle in a different repository.

view this post on Zulip Yury G. Kudryashov (Apr 07 2020 at 20:40):

One version of Chebyshev's inequality is now in mathlib, see docs

view this post on Zulip Yury G. Kudryashov (Apr 07 2020 at 20:41):

I factored out its proof from the next lemma while refactoring Borel spaces

view this post on Zulip Patrick Massot (Apr 07 2020 at 20:45):

But this features the weird ∫⁻

view this post on Zulip Yury G. Kudryashov (Apr 07 2020 at 20:47):

AFAIK, for a non-negative function Bochner integral equals lintegral.

view this post on Zulip Yury G. Kudryashov (Apr 07 2020 at 20:48):

And formalizing Chebyshev's inequality was not my goal.

view this post on Zulip Patrick Massot (Apr 07 2020 at 20:49):

I'm not complaining, I'm pointing out it's still hard to recognize.

view this post on Zulip Scott Morrison (Apr 07 2020 at 23:30):

Koundinya Vajjha said:

Markov's inequality and Chebyshev's Inequality were low hanging fruit since mathlib's measure theory library is very mature. So I proved those without too much hassle in a different repository.

Please make a PR!

view this post on Zulip Brandon B (Apr 07 2020 at 23:45):

Why can we create a pi type using the pi symbol \Pi but \Sigma doesn't work and instead we have to use sigma.mk or is there another command ?

view this post on Zulip Yury G. Kudryashov (Apr 07 2020 at 23:48):

When you declare a pi type, you use Π i, α i. When you define a variable of a pi type, you use λ i, f i.

view this post on Zulip Yury G. Kudryashov (Apr 07 2020 at 23:49):

When you declare a sigma type, you can use Σ i, α i. When you define a variable of a sigma type, you use either sigma.mk or ⟨i, y⟩.

view this post on Zulip Brandon B (Apr 08 2020 at 00:44):

ahh; thank you

view this post on Zulip Niclas Kupper (Apr 08 2020 at 12:23):

How can you rewrite the RHS of an equation? when I write rw add_comm at h for my equality h it always only rewrites the LHS. Thanks

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 12:26):

It rewrites the first occurrence of a+b it runs into

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 12:27):

Try rw add_comm X Y if you want to change X+Y into Y+X

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 12:27):

Or just rw add_comm X if you want to change the first X+something

view this post on Zulip Niclas Kupper (Apr 08 2020 at 12:31):

That worked, thanks!

view this post on Zulip Scott Morrison (Apr 08 2020 at 13:02):

Also try conv.

view this post on Zulip Johan Commelin (Apr 08 2020 at 13:30):

@Niclas Kupper https://github.com/leanprover-community/mathlib/blob/master/docs/extras/conv.md

view this post on Zulip Matt Watson (Apr 08 2020 at 13:55):

Complete noob question. Working on the natural numbers game and I want to use rw add_comm on t + t * b in t * n + t * b + t = t * n + t + t * b but I don't know how to apply it to t * b rather than just a naked variable

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 13:57):

Matt Watson said:

Complete noob question. Working on the natural numbers game and I want to use rw add_comm on t + t * b in t * n + t * b + t = t * n + t + t * b but I don't know how to apply it to t * b rather than just a naked variable

Try enclosing tb in parentheses like this: rw add_comm t (tb),

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 13:59):

I'm currently also doing the natural number game and I am stuck on level 9 in advanced proposition world. Is it possible to solve the problem without using either of cc, tauto and exfalso? Exfalso is introduced in the next problem, hence my question.

view this post on Zulip Matt Watson (Apr 08 2020 at 14:03):

Victor Ahlquist said:

Try enclosing t*b in parentheses like this: rw add_comm t  (t*b),

It didn't work for t and t*b, I think my problem was making assumptions about associativity. But knowing for sure that parenthesis worked helped solve it. Thankyou

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 14:05):

Yes a+b+c in Lean means (a+b)+c

view this post on Zulip Mario Carneiro (Apr 08 2020 at 14:05):

you need add_right_comm here

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 14:06):

I'm not sure we prove that at all

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 14:06):

I can't remember, I think I just went for the stuff that made simp work

view this post on Zulip Mario Carneiro (Apr 08 2020 at 14:07):

simp only needs add_left_comm because it likes right associating addition

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 14:07):

Advanced prop world level 9 I think someone else pointed out that they wanted to use exfalso. I'll take a look at this today

view this post on Zulip Mario Carneiro (Apr 08 2020 at 14:07):

which is too bad since the pretty printer prefers left associated

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 14:07):

You can look at my solutions in the repo

view this post on Zulip Mario Carneiro (Apr 08 2020 at 14:08):

you could make + right associative...

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 14:09):

Kevin Buzzard said:

Advanced prop world level 9 I think someone else pointed out that they wanted to use exfalso. I'll take a look at this today

Very nice, thanks.

view this post on Zulip Matt Watson (Apr 08 2020 at 14:19):

Does the page use local storage, or have I lost my entire game if I crashed the tab?

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 14:19):

you can just go to any level at any time

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 14:20):

all you lose is the colouring in dots

view this post on Zulip Johan Commelin (Apr 08 2020 at 14:20):

@Kevin Buzzard You should ask for some help with improving the machinery of the game on that reddit page

view this post on Zulip Kenny Lau (Apr 08 2020 at 14:20):

Kevin Buzzard said:

you can just go to any level at any time

the levels are a lie

view this post on Zulip Johan Commelin (Apr 08 2020 at 14:20):

Probably lots of people over there that would love to add a "use local storage" feature

view this post on Zulip Johan Commelin (Apr 08 2020 at 14:21):

Kenny Lau said:

Kevin Buzzard said:

you can just go to any level at any time

the levels are a lie

There are no levels... you only imagine them

view this post on Zulip Bryan Gin-ge Chen (Apr 08 2020 at 14:21):

I think the progress is saved using cookies rather than local storage.

view this post on Zulip Kenny Lau (Apr 08 2020 at 14:21):

Johan Commelin said:

Probably lots of people over there that would love to add a "use local storage" feature

like this game i enjoyed from many years ago: https://alf.nu/RegexGolf

view this post on Zulip Andrew Ashworth (Apr 08 2020 at 14:23):

wow i'm irrationally annoyed at the levels beyond classic

view this post on Zulip Kenny Lau (Apr 08 2020 at 14:25):

why?

view this post on Zulip Andrew Ashworth (Apr 08 2020 at 14:29):

i'm remembering a specific set of exam questions in my compilers class that "pure" regex (dfas) cannot be used to count and quantify, and getting them to do it is a hack. of course regular people use regex for this all the time, so maybe i was just insufficiently traumatized by my instructor

view this post on Zulip Marc Huisinga (Apr 08 2020 at 14:33):

regexp with backtracking can also lead to exponential blowup iirc

view this post on Zulip Marc Huisinga (Apr 08 2020 at 14:34):

so i think there are good reasons to restrict yourself to a regular subset when using regexes

view this post on Zulip Marc Huisinga (Apr 08 2020 at 14:41):

ah, this site was down for a while, but this is the post that i read years ago: https://swtch.com/~rsc/regexp/regexp1.html

view this post on Zulip Matt Watson (Apr 08 2020 at 14:47):

Not only that, but having to support a non-regular language makes a language slower when dealing with expressions that are regular.

view this post on Zulip Scott Morrison (Apr 08 2020 at 15:01):

That is an incredibly unfortunate story. :-(

view this post on Zulip Johan Commelin (Apr 08 2020 at 15:10):

Andrew Ashworth said:

of course regular people use regex for this all the time,

Sure, regular people do... but what about expressive people?

view this post on Zulip Niclas Kupper (Apr 08 2020 at 15:14):

I'm currently on the first advanced multiplication world level in the natural number game and I used cases and my equation got a term zero instead of 0, which I can not manipulate with the usual proofs. What can I do now?

view this post on Zulip Niclas Kupper (Apr 08 2020 at 15:14):

It might be because I tried to define a lemma in the proof

view this post on Zulip Matt Watson (Apr 08 2020 at 15:15):

@Johan Commelin Or push down automatons?

view this post on Zulip Johan Commelin (Apr 08 2020 at 15:16):

@Niclas Kupper Trying to define a lemma in a proof seems like it cannot work...

view this post on Zulip Johan Commelin (Apr 08 2020 at 15:17):

Can you copy paste all the code the entire code block (starting with lemma ... until ... end

view this post on Zulip Johan Commelin (Apr 08 2020 at 15:17):

```lean
put code here
```

view this post on Zulip Niclas Kupper (Apr 08 2020 at 15:17):

intro p1,
intro p2,
intro k,
induction b with d hd,
rw mul_zero a at k,
exact p2 k,
lemma pos_mul (a b : mynat) : a * b = 0 → a = 0 ∨ b = 0 :=
begin
  intro k,
  cases a with d,
  ```

view this post on Zulip Niclas Kupper (Apr 08 2020 at 15:18):

This is where the problem appeared, I assume that normally I would put a lemma like that in its own file?

view this post on Zulip Andrew Ashworth (Apr 08 2020 at 15:30):

use the have keyword / tactic

view this post on Zulip Andrew Ashworth (Apr 08 2020 at 15:31):

if you want to do it inside a proof; normally such a fundamental fact would be broken out separately though, as you say

view this post on Zulip Niclas Kupper (Apr 08 2020 at 15:32):

How do I want to use have?

view this post on Zulip Andrew Ashworth (Apr 08 2020 at 15:33):

https://leanprover.github.io/theorem_proving_in_lean/propositions_and_proofs.html#introducing-auxiliary-subgoals

view this post on Zulip Niclas Kupper (Apr 08 2020 at 15:34):

Thanks!

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 15:44):

Will using cases with a mynat always separate into cases zero and successor?

view this post on Zulip Donald Sebastian Leung (Apr 08 2020 at 15:44):

Yes

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 15:45):

Thanks

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 15:55):

Using cases with any inductive type separates into the constructors for that type. For nat this is zero / succ, for P \or Q this is a proof of P / a proof of Q etc.

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 15:59):

Thanks, googling some of those terms brought up a nice page. I'll be sure to read the entire "Theorem proving in Lean" once I'm done with the game.

view this post on Zulip Matt Watson (Apr 08 2020 at 16:03):

Why are propositions distinct from inhabitation of types?

view this post on Zulip Matt Watson (Apr 08 2020 at 16:05):

Or am I importing half-understood ideas from a different type theory?

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 16:06):

The Prop universe is proof irrelevant which means that if P : Prop and a b : P then a = b definitionally.

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 16:07):

This makes some type theory people unhappy but it seems to make mathematicians happy

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 17:05):

Is there any reason why proof of contrapositive reasoning is not added to theorem list after advanced proposition world?

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 17:11):

I guess I just randomly wrote a load of worlds and didn't particularly plan anything in some coherent way. What do you suggest I do? I'm going to make some minor updates later on today.

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 17:18):

Well I have no particular suggestion. Having to "redo" a proof backwards has been useful in learning how to use lean. I was just wondering if this was intended or not.

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 17:19):

I really appreciate the work you have done with the game. This is a really exciting way to study mathematics.

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 17:21):

Oh -- are you saying I failed to add it to some list which it should be on? Sorry, I misunderstood. Probably the answer is that the current version of the Lean game maker forces me to do some things twice -- once in Lean and once in a comment so that it's registered by the system to add to a list, and maybe I failed to do it here. This was what caused the pow_succ fail: the theorem list had an incorrect version of pow_succ because of a copy paste fail.

view this post on Zulip Victor Ahlquist (Apr 08 2020 at 17:23):

Oh I see. I have been using the list of theorems to the right as a kind of "Allowed theorems to use" list(which is also handy because the list has the names), which is why I wondered.

view this post on Zulip Matt Watson (Apr 08 2020 at 18:05):

Piece of feedback: I seem to alternate between feeling completely lost, and like the body text is spoiling the answer.
Perhaps the more direct instructions could be hidden behind a spoiler tag so we can struggle on our own a bit?

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 18:09):

I absolutely agree. Firstly, I need a competent editor -- I waffle and waffle. Secondly, unfortunately, the infrastructure is not there yet for me to be able to implement the spoiler tag stuff, but I can add it as an issue to Mohammad's game maker -- I had independently thought of this recently.

view this post on Zulip Matt Watson (Apr 08 2020 at 18:53):

If you add something like this to editor.main.css

.hover-item {
    color: #fff;
}

.hover-item:hover {
    color: #000;
}

and then wrap the spoiler in <span class="hover-item"> it should work

view this post on Zulip Matt Watson (Apr 08 2020 at 18:54):

I can see about writing an extension to showdown to make it a little more erganomic

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 18:55):

Yeah but I don't know what a css file is -- you could maybe put some comment on the issue I opened on Mohammad's repo (he is about to defend his thesis viva so we might not hear from him for a few days)

view this post on Zulip Matt Watson (Apr 08 2020 at 18:55):

(showdown doesn't touch the span tags, adding them to the js objects worked but I'm not sure if lean will eat them)

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 18:57):

If you want to make some PR and tell me how to change my repo I would be interested.

view this post on Zulip Matt Watson (Apr 08 2020 at 18:59):

It looks like you're pulling the relevant file in during the build/deploy process, so I can send the PR to Mohammad's repo.

view this post on Zulip Kevin Buzzard (Apr 08 2020 at 19:00):

but then presumably I have to indicate which part of the Lean file should be folded, somehow?

view this post on Zulip Matt Watson (Apr 08 2020 at 19:01):

Yeah, the thing I proposed would be a fast/simple but not great way of doing it.

More correct would be to write an extension for the markdown formatter (called showdown), then you'd just wrap the hidden section in something like >! Text to hide <

view this post on Zulip Matt Watson (Apr 08 2020 at 19:02):

That's one common syntax. Another is [spoiler] [/spoiler]

view this post on Zulip Matt Watson (Apr 08 2020 at 19:05):

I'll look into doing it properly (if you don't hear from me in a couple of days it means I got sidetracked). In the interim, here is other formatting syntax that should work with what you're already running if you were not already aware of it http://demo.showdownjs.com/

view this post on Zulip Matt Watson (Apr 08 2020 at 19:49):

How do I make rw happen on a hypothesis?
Specifically I have

a b u : mynat,
ht : a + u = b + u → a = b,
h : a + succ u = b + succ u
⊢ a + u = b + u

and I'm trying to use rw add_succ on both sides of h, but I keep getting 'did not find instance of pattern'

view this post on Zulip Anas Himmi (Apr 08 2020 at 19:52):

rw [add_succ,add,succ] at h

view this post on Zulip Matt Watson (Apr 08 2020 at 19:53):

Thanks

view this post on Zulip Brandon B (Apr 09 2020 at 00:19):

What exactly is a tactic under the hood? Is it just syntactic sugar for function composition? Is it a macro?

view this post on Zulip Bryan Gin-ge Chen (Apr 09 2020 at 00:25):

They're functions / programs that manipulate the "tactic state". You can read more in the tactic writing tutorial.

view this post on Zulip Scott Morrison (Apr 09 2020 at 01:52):

I found https://doi.org/10.1145/3110278 really helpful.

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 14:20):

The link from https://github.com/ImperialCollegeLondon/natural_number_game/blob/master/WHATS_NEXT.md to the lean web editor seems to be broken.

view this post on Zulip Bryan Gin-ge Chen (Apr 09 2020 at 14:29):

The correct link is https://github.com/kbuzzard/xena/tree/master/Maths_Challenges/README.md . I'll open a PR if there isn't one already.

edit: ImperialCollegeLondon/natural_number_game#66

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 15:01):

Thanks, I haven't really used Github before so wasn't sure how to report it.

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 15:03):

Going to read up on the lean documentation now at least. This seems like a productive thing to use my free time on.

view this post on Zulip Will P (Apr 09 2020 at 15:14):

Hi, thanks for all the work put into lean. I'm having a go at the natural numbers game and I got stuck at level 10 on the advanced addition. I'm not sure exactly how to use not equals during a proof. My current attempt is

cases b with d,
refl,
exfalso ,
rw add_succ at H,
have q := succ_ne_zero(a + d) at H,
rw H at q,

a d : mynat,
H : succ (a + d) = 0,
q : 0  0
 false

I've got 0 /=0 but no way of making that false

view this post on Zulip Kenny Lau (Apr 09 2020 at 15:17):

hint: use the following code to enable syntax highlighting:

```lean
[your code here]
```

view this post on Zulip Kenny Lau (Apr 09 2020 at 15:18):

Also, please copy the tactic state after the final comma.

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 15:28):

Nothing seems to happen when I'm using the lean web editor. I pressed the first "try it!" button here: https://leanprover.github.io/theorem_proving_in_lean/introduction.html , but I can't see the current goal only the block of code.

view this post on Zulip Marc Huisinga (Apr 09 2020 at 15:29):

that proof is in term mode, so it won't have a goal view

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 15:30):

The community web editor is better.

view this post on Zulip Marc Huisinga (Apr 09 2020 at 15:30):

chapter 5 introduces tactics, here's one example

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 15:32):

Ah thanks

view this post on Zulip Kenny Lau (Apr 09 2020 at 15:32):

@Will P change your last two lines to:

apply succ_ne_zero (a + d),
exact H,

view this post on Zulip Marc Huisinga (Apr 09 2020 at 15:35):

(deleted)

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 15:36):

About Will P's question: I also had some times when doing the natural number game when it would have been great to get a "trivial" hypothesis such as 0=0. I tried the have command, but it did not work. Is there any other way to get an equality?

view this post on Zulip Kenny Lau (Apr 09 2020 at 15:37):

have h : 0 = 0,
refl,

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 15:37):

If you have

q : 0 ≠ 0
⊢ false

then you can apply q and then refl because q is 0 = 0 -> false

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 15:40):

Ah, I tried have h := 0=0, which only gave me a h: Prop. Thanks for the answers

view this post on Zulip Kenny Lau (Apr 09 2020 at 15:41):

h := 0=0 means h is defined to be 0=0, which is a Prop

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 15:43):

I see, hopefully all of this will make more sense after reading the book.

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 15:50):

Be clear about the difference between a Proposition (a true/false statement) and its proof. In mathematics we are very vague about this, we have our own conventions which seem to work fine but don't stand up to scrutiny. When we say "by theorem 10" we mean "by the fact that we proved theorem 10"; theorem 10 is just a statement. A true/false statement, otherwise known as a Proposition in Lean, is P : Prop. It's proof is h : P. For example injective f : Prop := \forall x y, f x = f y -> x = y is the definition of injectivity. There is no proof here, it's a definition of a true/false statement, and its truth value depends on what f is. But h : injective succ := <proof that succ is injective> is a proof. The propositions are types, and the proofs are terms. Be clear about what level you are working at.

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 16:56):

Kevin Buzzard said:

Be clear about the difference between a Proposition (a true/false statement) and its proof. In mathematics we are very vague about this, we have our own conventions which seem to work fine but don't stand up to scrutiny. When we say "by theorem 10" we mean "by the fact that we proved theorem 10"; theorem 10 is just a statement. A true/false statement, otherwise known as a Proposition in Lean, is P : Prop. It's proof is h : P. For example injective f : Prop := \forall x y, f x = f y -> x = y is the definition of injectivity. There is no proof here, it's a definition of a true/false statement, and its truth value depends on what f is. But h : injective succ := <proof that succ is injective> is a proof. The propositions are types, and the proofs are terms. Be clear about what level you are working at.

Thanks for the elaborate reply, now it is very clear why h : 0=0 ,is used

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 18:37):

By the way, a project of "perfectoid spaces" was mentioned after finishing the game. It said you needed a "whole lot of commutative algebra" to do that. Does this mean PhD level?

view this post on Zulip Marc Huisinga (Apr 09 2020 at 18:44):

Victor Ahlquist said:

By the way, a project of "perfectoid spaces" was mentioned after finishing the game. It said you needed a "whole lot of commutative algebra" to do that. Does this mean PhD level?

https://arxiv.org/abs/1910.12320

view this post on Zulip Victor Ahlquist (Apr 09 2020 at 18:47):

Looks like a yes then.

view this post on Zulip Filip Szczepański (Apr 09 2020 at 22:10):

Is there anything I can do when the Lean interpreter on the Natural Number Game gets stuck, besides refreshing the page and losing my progress?

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 22:13):

no progress is kept. You can go to any level at any time.

view this post on Zulip Bryan Gin-ge Chen (Apr 09 2020 at 22:14):

What's causing the interpreter to get stuck? Is it something you can reproduce?

view this post on Zulip Filip Szczepański (Apr 09 2020 at 22:14):

That's true. I appreciate seeing how far I've gotten, though

view this post on Zulip Filip Szczepański (Apr 09 2020 at 22:15):

One time I got it stuck with repeat { rw add_comm }, and this time it was something else with repeat

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 22:15):

You can get a tactic block which loops, but in VS Code this isn't a problem. Is it a problem in NNG?

view this post on Zulip Filip Szczepański (Apr 09 2020 at 22:16):

Yeah, just on the NNG website

view this post on Zulip Filip Szczepański (Apr 09 2020 at 22:17):

I wouldn't mind going through NNG in vscode, but it seems the website is the recommended way? Also vscode doesn't list the tactics and theorems

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 22:17):

You're right, and I don't really know how to solve this.

view this post on Zulip Bryan Gin-ge Chen (Apr 09 2020 at 22:18):

I can't seem to get the web editor to loop. If you run into another loop, please paste the full code so I can take a look.

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 22:18):

@Bryan Gin-ge Chen try going to advanced addition world at http://wwwf.imperial.ac.uk/~buzzard/xena/natural_number_game/ , level 5, and then try repeat {rw add_comm}. This loops. Unsurprisingly, you get "Lean is busy...". But it doesn't go away

view this post on Zulip Filip Szczepański (Apr 09 2020 at 22:19):

Obviously, the interpreter can just keep going between a+b and b+a forever

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 22:19):

Right. But in VS Code if you just delete the line repeat {rw add_comm} everything goes back to normal.

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 22:20):

In NNG it seems that this breaks the game forever, you can go back to the overworld and then click on another world and any level and Lean is still busy

view this post on Zulip Kevin Buzzard (Apr 09 2020 at 22:25):

https://github.com/mpedramfar/Lean-game-maker/issues/6

view this post on Zulip Bryan Gin-ge Chen (Apr 09 2020 at 22:29):

Interesting. my wild guess would be because the web editor runs single-threaded (?) and so nothing is able to interrupt the loop. For the NNG, maybe you could wrap repeat in try_for 100000 to protect users from this.

view this post on Zulip Bryan Gin-ge Chen (Apr 09 2020 at 22:30):

Well, I'm not sure what numbers would be good to use in try_for, maybe 100000 is still too low.

view this post on Zulip Filip Szczepański (Apr 09 2020 at 22:38):

I think the Lean interpreter is running in something like a web worker, otherwise I'd expect the whole tab to freeze up

view this post on Zulip Scott Morrison (Apr 09 2020 at 22:39):

My son did exactly this, and it really upset him when he lost his progress. :-) It was a good life lesson...

view this post on Zulip Bryan Gin-ge Chen (Apr 09 2020 at 23:05):

Yep, there's one web worker for the Lean server and one worker for Monaco (the text editor).

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:14):

The link to "2 add 2 isn't 5" from here https://github.com/kbuzzard/xena/blob/master/Maths_Challenges/README.md is broken

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:15):

Actually all of the links except the first two appears to be broken

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:21):

Nobody ever does these challenges, I don't think I've ever got any feedback from them. Thanks for letting me know.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:23):

Oh, the first two were nice to do after NNG. Guess I'll look for other things to do.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:23):

They'll all be fixed in 5 minutes :-)

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:23):

Nice, thanks :)

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:29):

Links to questions should now all work, I'll check hints and solutions. Thanks again.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:34):

Thanks, they're working now

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:38):

By the way, I saw you mentioned in an old reddit thread that there still was some undergrad math that needed to be done in Lean. Is this still the case?

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:43):

3rd year undergraduate maths there's lots.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:43):

1st and 2nd year we're basically covered apart from contour integrals

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:44):

3rd year undergrad we have most of a basic number theory course but as far as I know we don't have any of: ideals in a number field factor uniquely into prime ideals, finiteness of class group, rank of unit group.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:45):

we have a bunch of commutative algebra but no homological algebra

view this post on Zulip Johan Commelin (Apr 10 2020 at 13:45):

Well... some people are working on combinatorics/probability theory/graph theory... but there are huge holes there.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:46):

Oh here's a list of random things we don't have: https://github.com/kbuzzard/xena/blob/master/many_maths_challenges.txt

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:48):

Oh, some of those topics definitely sound approachable. I'm a 2nd year undergrad, but in Swedish school system so not sure how things translate. I'll have a lot of free time this summer and some free time the weeks until then so I'll definitely start looking into this.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:48):

Thanks for the list!

view this post on Zulip Patrick Massot (Apr 10 2020 at 13:49):

homological algebra is coming, I've seen many PRs about this recently

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:49):

I'm working with a bunch of 2nd year undergraduates on stuff this summer, it was all going to happen at Imperial College but now it's probably going to happen online, you'd be welcome to join us -- most people will be beginners.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:50):

homological algebra has in some sense been coming for some time. Another way of looking at it is that a mathematician writes "let Mn1MnMn+1\cdots\to M_{n-1}\to M_n\to M_{n+1}\to \cdots be an exact sequence of abelian groups, and then we spend months trying to figure out how best to say that in Lean without getting caught up in type theory issues.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:51):

or category theory issues

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:52):

Kevin Buzzard said:

I'm working with a bunch of 2nd year undergraduates on stuff this summer, it was all going to happen at Imperial College but now it's probably going to happen online, you'd be welcome to join us -- most people will be beginners.

Wow that would be great. What would the mathematical prerequisites be?

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:53):

2nd year undergrad?

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 13:53):

Whatever you show up with, really.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:58):

Neat, I'll just practice using lean until then in that case.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 13:58):

It is really impressing that there's already so much math formalized in lean.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:01):

In 2017 there was nothing.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:01):

Definitions of rings, groups, top spaces, basic stuff about compact spaces, hardly any theorems about anything else. Loads and loads and loads of theorems about lists finite sets though, which turn out to be really important.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 14:02):

I'm looking forward to seeing how this will influence mathematics

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:02):

Most stuff written by Mario Carneiro and Johannes Hoelzl, who have a computer science background. Then mathematicians started to get involved and the focus of the library changed much more to undergraduate level mathematics

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 14:03):

Ah I see. It is nice that there's some cooperation between different subjects going on.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:03):

I should say that Mario almost certainly would not say there was nothing -- there was a ton of stuff in late 2017 which was of foundational importance.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:03):

But if you look at what there was and compare with the things taught to maths undergraduates, there was very little.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:04):

Because we don't teach them that the union of two finite sets is finite, this doesn't need a proof as far as we are concerned :-) In Lean this sort of thing needs to be proved, and then you have to decide what the definition of a finite set is, and then suddenly you are wrestling with foundational type theory issues.

view this post on Zulip Patrick Massot (Apr 10 2020 at 14:05):

Even at that time there was much more general topology than what we teach undergrads.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:06):

Yes that is true, it was some weird outlier.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:06):

Probably all the results in my 2nd year topology course were there.

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:07):

But I am pretty sure there was no first isomorphism theorem for groups or rank-nullity for vector spaces in 2017.

view this post on Zulip Patrick Massot (Apr 10 2020 at 14:08):

Note there was a lot of topology but no normed space.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 14:08):

I guess some maths is easier to formalize than others?

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 14:09):

Although that's a wild guess from my side.

view this post on Zulip Filip Szczepański (Apr 10 2020 at 14:13):

What happens when I write have foo := bar, and there was already something with the name foo in scope?

view this post on Zulip Donald Sebastian Leung (Apr 10 2020 at 14:16):

You get two foos in your context, and IIRC the latest foo shadows the earlier one (so later tactics referring to foo would only see the latest one)

view this post on Zulip Filip Szczepański (Apr 10 2020 at 14:16):

Ok, that's fairly convenient. Thanks.

view this post on Zulip Donald Sebastian Leung (Apr 10 2020 at 14:17):

This is one of the things that sometimes gets me in Lean, but doesn't happen in Coq. Does anyone know the rationale behind this design decision?

view this post on Zulip Patrick Massot (Apr 10 2020 at 14:18):

Honestly I also wish Lean would rise at least a warning in this situation.

view this post on Zulip Patrick Massot (Apr 10 2020 at 14:18):

Here Lean feels very pythonic we're-all-consenting-adults.

view this post on Zulip Filip Szczepański (Apr 10 2020 at 14:47):

I finally finished mul_left_cancel

view this post on Zulip Filip Szczepański (Apr 10 2020 at 14:47):

I bet my proof is overcomplicated

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 14:48):

My proof looks pretty long

view this post on Zulip Filip Szczepański (Apr 10 2020 at 14:51):

https://gist.github.com/FreeFull/01d57489ac996db3ea2f8e31254d466c This is mine. I didn't use assumption because I didn't know about it

view this post on Zulip Filip Szczepański (Apr 10 2020 at 14:51):

Not too nicely formatted either

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 16:19):

I tried downloading and installing leanprover and commands like #eval 1+1 work without trouble. However when I try importing things such as import data.finset algebra.big_operators tactic.ring, I get a file not found error. Any idea what could be causing this?

view this post on Zulip Bryan Gin-ge Chen (Apr 10 2020 at 16:54):

Did you follow all the instructions for your OS here and then follow the instructions to create a project here?

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 17:15):

Note however that you cannot use mathlib, and in particular any imports, in the file test.lean created above. To use mathlib you will need to set up or download a Lean project. You should now read instructions about creating and working on Lean projects.

What is your OS? Does this comment (at the bottom of the install files) apply to you?

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 19:13):

Bryan Gin-ge Chen said:

Did you follow all the instructions for your OS here and then follow the instructions to create a project here?

Ah no, I did not follow the instructions to create a project only the instructions on the install page. I'll try this

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 19:26):

Great, now it works perfectly! Thanks for the help

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 19:34):

Not sure how I managed to miss that last message

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 19:42):

I specially put it into the docs a couple of weeks ago because people keep asking this :-)

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 19:43):

Maybe I'll put it in flashing red letters :-)

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 19:43):

Haha, as you posted it I can recall reading it and then promptly forgetting about it.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 20:05):

Chapter 2 was an interesting but tough read, reminds me of my course in Java programming

view this post on Zulip Kevin Buzzard (Apr 10 2020 at 20:05):

Chapter 2 of the installation instructions?

view this post on Zulip Filip Szczepański (Apr 10 2020 at 20:06):

I have hb : b = b + d + c and I'm wondering if there's a more straightforward way to get to 0 = d + c than going through ← add_zero, add_assoc and add_left_cancel

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 20:07):

Kevin Buzzard said:

Chapter 2 of the installation instructions?

Haha no, chapter 2 of theorem proving in lean.

view this post on Zulip Victor Ahlquist (Apr 10 2020 at 20:15):

Filip Szczepański said:

I have hb : b = b + d + c and I'm wondering if there's a more straightforward way to get to 0 = d + c than going through ← add_zero, add_assoc and add_left_cancel

I'm new to Lean so this is probably wrong, but perhaps you could leave out add_zero.

view this post on Zulip Mario Carneiro (Apr 10 2020 at 23:36):

Donald Sebastian Leung said:

You get two foos in your context, and IIRC the latest foo shadows the earlier one (so later tactics referring to foo would only see the latest one)

Patrick Massot said:

Honestly I also wish Lean would rise at least a warning in this situation.

Actually lean does raise a warning in this situation, at least in some cases, especially after a tactic fails; it will suggest that you run the dedup tactic

view this post on Zulip Mario Carneiro (Apr 10 2020 at 23:42):

Donald Sebastian Leung said:

This is one of the things that sometimes gets me in Lean, but doesn't happen in Coq.

What does Coq do in this situation? It seems to me that if we gave a warning on every name shadowing we would get a ridiculous number of false positives, especially because have := ... is deliberately reusing and shadowing the this variable

view this post on Zulip Filip Szczepański (Apr 11 2020 at 04:59):

Having some trouble figuring out how to get started on le_total in the natural number game. I'm guessing this is the next level that people tend to get stuck on, after mul_left_cancel?

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 05:51):

I can't recall exactly how I did but I think I started with induction on b

view this post on Zulip Shing Tak Lam (Apr 11 2020 at 05:55):

I think you need to revert a first.

view this post on Zulip Shing Tak Lam (Apr 11 2020 at 06:00):

So my proof starts with

  revert a,
  induction b with b IH,

view this post on Zulip Filip Szczepański (Apr 11 2020 at 06:22):

Thanks, the revert certainly seems handy

view this post on Zulip Donald Sebastian Leung (Apr 11 2020 at 06:27):

Mario Carneiro said:

Donald Sebastian Leung said:

This is one of the things that sometimes gets me in Lean, but doesn't happen in Coq.

What does Coq do in this situation? It seems to me that if we gave a warning on every name shadowing we would get a ridiculous number of false positives, especially because have := ... is deliberately reusing and shadowing the this variable

Coq simply prevents you from reusing hypothesis names by raising an error. On the other hand, if you don't explicitly name your hypotheses in Coq then Coq just auto-generates gibberish hypothesis names instead of (re-using) a nice name such as this

view this post on Zulip Mario Carneiro (Apr 11 2020 at 06:58):

One thing we could do is make have have the same behavior as replace, that is, if the name would collide then the old version is deleted

view this post on Zulip Mario Carneiro (Apr 11 2020 at 06:59):

however this could still break some proofs because you can refer to shadowed variables using assumption and other things that enumerate the local context

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 07:17):

Shing Tak Lam said:

I think you need to revert a first.

What's the purpose of revert in this case? Will it lead to a shorter proof?

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 07:18):

induction b with b IH,
right,
exact zero_le a,
cases IH with p q,
left,
exact le_succ a b p,
cases q with c,
cases c,
use succ(0),
rw q_h,
refl,
right,
use c,
rw q_h,
rw succ_add,
rw add_succ,
refl,

I redid it and got this.

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 07:20):

Actually the second last line is redundant.

view this post on Zulip Shing Tak Lam (Apr 11 2020 at 07:21):

This is my proof with revert a

  revert a,
  induction b with b IH,
    intro a,
    right,
    exact zero_le _,
    intro a,
    cases a with a,
      left,
      exact zero_le _,
      cases (IH a),
        left,
        exact succ_le_succ a b h,
        right,
        exact succ_le_succ b a h,

So it's a bit shorter?

view this post on Zulip Donald Sebastian Leung (Apr 11 2020 at 07:21):

Victor Ahlquist said:

Shing Tak Lam said:

I think you need to revert a first.

What's the purpose of revert in this case? Will it lead to a shorter proof?

Notice the difference in your IH with and without revert.

view this post on Zulip Shing Tak Lam (Apr 11 2020 at 07:23):

But the main reason was to do with the induction hypothesis. The IH after using revert a is much easier to use than the one without.

view this post on Zulip Kevin Buzzard (Apr 11 2020 at 07:24):

Filip Szczepański said:

I have hb : b = b + d + c and I'm wondering if there's a more straightforward way to get to 0 = d + c than going through ← add_zero, add_assoc and add_left_cancel

If you're working with usual Lean naturals then the omega tactic will solve this for you:

import tactic

example (b c d : ) (hb : b = b + d + c) : 0 = d + c := by omega

But if you're working with home-grown naturals like mynat then you might have to work harder.

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 07:24):

Ah I see, it does look like a more powerful hypothesis.

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 07:27):

Guess I'm just scared of quantifiers in Lean

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 13:33):

There's not much explanation of this in the book, but why does a list have Type u \r Type u as it's type?

view this post on Zulip Kenny Lau (Apr 11 2020 at 13:34):

Given a type \a, list \a is a type

view this post on Zulip Kenny Lau (Apr 11 2020 at 13:34):

So list itself sends types to types

view this post on Zulip Victor Ahlquist (Apr 11 2020 at 13:35):

Ah right, that makes sense thanks.

view this post on Zulip Grayson Burton (Apr 11 2020 at 17:34):

Why don't interactive theorem provers (including Lean to my knowledge) provide a recursor for Type? Does it cause ""fun"" I'm not noticing in my few minutes' consideration?

view this post on Zulip Johan Commelin (Apr 11 2020 at 17:35):

What would that look like?

view this post on Zulip Grayson Burton (Apr 11 2020 at 17:41):

def {u} wacky: Type  Type u
| (  ) := ulift 
| (string  ) := ulift string
| α := ulift α

Something like this?

view this post on Zulip Grayson Burton (Apr 11 2020 at 17:42):

Obviously a contrived example :)

view this post on Zulip Kenny Lau (Apr 11 2020 at 17:43):

Type is not inductive.

view this post on Zulip Kenny Lau (Apr 11 2020 at 17:43):

you can use if then else instead.

view this post on Zulip Grayson Burton (Apr 11 2020 at 17:45):

Oh, right. Of course, thanks.

view this post on Zulip David Wärn (Apr 11 2020 at 19:03):

Isn't (ℕ → ℕ) ≠ (string → ℕ) unprovable? If so you'd have little hope of being able to functions as above

view this post on Zulip Reid Barton (Apr 11 2020 at 19:20):

For anything like this you'd actually want to do, you'd probably want to use classes instead.

view this post on Zulip Mario Carneiro (Apr 11 2020 at 22:57):

Assuming you want an actual recursor and not just pick off a few cases, it's not consistent. Because there are types you can construct using choice that are provably different from every "constructable" type (since there are countably many constructable types and so there is some aleph less than aleph_(aleph_1) that was missed)

view this post on Zulip Brandon B (Apr 11 2020 at 23:20):

So I see one aim of Lean would be to implement as much of modern mathematics into it as possible, starting with all of undergrad math as Kevin Buzzard is doing so that research level math can eventually be done. My question is, if we already have a bunch of theorems that have been proved with paper and pencil, why can't we just add them in as constants (basically assuming they're true w/o explicit construction of a proof) and build from there?

view this post on Zulip Andrew Ashworth (Apr 11 2020 at 23:23):

the exact formal statement of a mathematical theorem can be extremely subtle, at times

view this post on Zulip Andrew Ashworth (Apr 11 2020 at 23:24):

using them all over the place defeats the purpose of formalization, in terms of checking correctness of proofs

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:24):

I think this is fine in limited quantities

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:24):

FAbstracts is using essentially this method

view this post on Zulip Andrew Ashworth (Apr 11 2020 at 23:25):

i don't think there's any getting around using them here and there, especially for results that depend on a whole bunch of other material

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:26):

Maybe I'm not looking at the right theorems, but it's not very often I see a theorem where the statement is tractable but the proof is not, that I want to assume for something else

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:26):

most of the time the theorem would be some work but not unreasonably so

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:27):

and I feel much better about the result afterwards

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:27):

or else the statement of the theorem is already hopeless requiring some big library development that doesn't yet exist

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:28):

after all, it's not enough just to state the theorem, you also have to be able to prove the basic consequences of all the definitions used in the theorem if you expect to build on top of an assumption with that statement

view this post on Zulip Scott Morrison (Apr 11 2020 at 23:40):

Note in Mario's statement the all-important clause "that I want to assume for something else". FLT would be a great counterexample to his claim otherwise, but actually fits perfectly. :-) We are very far from being able to state the "actual usable theorems" associated to FLT.

view this post on Zulip Brandon B (Apr 11 2020 at 23:51):

On another note - is there a way to compose functions left to right in Lean? e.g. it gets tiresome doing h(g(f(x))) when I'd rather do something like x>f>g>h

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:54):

I recall seeing isabelle using the |> notation for this, although we will have to take that notation back from the useless option.lhoare

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:55):

You can use h $ g $ f $ x to make the chain more linear but that doesn't resolve the order

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:55):

Oh wait, I just remembered that we already did this

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:55):

it's $<

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:55):

in one of the mathlib files

view this post on Zulip Andrew Ashworth (Apr 11 2020 at 23:55):

... I wish it was |>, that's the pipeline operator in multiple fp languages, not just isabelle

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:56):

now that we've taken over core we can delete those notations

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:56):

which have been used literally zero times

view this post on Zulip Mario Carneiro (Apr 11 2020 at 23:57):

even the functions they abbreviate are never used

view this post on Zulip Anas Himmi (Apr 12 2020 at 01:27):

how to prove this?

lemma nat.rec_on_sup {C :   Prop} (n i: ) (hp:n  i) (hi: C i) (hr :  (n : ), C n  C (nat.succ n)) : C n := sorry

when i do a proof by induction like this:

begin
induction n with n hn,
{ rwa [eq_bot_iff.mpr hp] at hi},
sorry
end

i get this goal state:

1 goal
case nat.succ
C :   Prop,
i : ,
hi : C i,
hr :  (n : ), C n  C (nat.succ n),
n : ,
hn : n  i  C n,
hp : nat.succ n  i
 C (nat.succ n)

so i can't access hn

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 07:43):

Brandon B said:

starting with all of undergrad math as Kevin Buzzard is doing

I might have been one of the people who thought it was a good idea to focus on undergraduate mathematics, but when it comes to doing it, much of the community is involved and I am only playing an extremely small part. For example the basic theory of multivariable calculus, manifolds etc is (a) undoubtedly undergraduate mathematics (b) extremely subtle to do in a theorem prover (c) something I have had absolutely nothing to do with and (d) currently making huge progress thanks to people like @Sebastien Gouezel and @Patrick Massot and @Yury G. Kudryashov and others. I am the loud Lean public relations guy with access to a mathematical audience and this plays some role, but this is not "my project" in any way: it is the project I am passionate about, but that's something different.

view this post on Zulip Jason KY. (Apr 12 2020 at 11:18):

Anas Himmi said:

how to prove this?

I solved it by taking the cases of ini \le n then doing an induction on i<ni < n

import tactic

lemma nat.rec_on_sup
{C :   Prop} (n i : ) (hp : n  i) (hi : C i)
(hr :  (n : ), C n  C (nat.succ n)) : C n :=
begin
  cases lt_or_eq_of_le hp,
    {induction h with k hle ht,
      {exact hr i hi},
      replace hle : i + 1  k := hle,
      refine hr k (ht $ le_trans (nat.le_succ i) hle)},
    rwa h
end

view this post on Zulip Anas Himmi (Apr 12 2020 at 11:23):

Woow thank you!

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:27):

Mario Carneiro said:

Maybe I'm not looking at the right theorems, but it's not very often I see a theorem where the statement is tractable but the proof is not, that I want to assume for something else

So in more serious mathematics this phenomenon shows up a lot -- I would say it's more the rule than the exception. But the point remains that at the level I'm talking about we cannot currently state the results we are interested in because we don't have the definitions in mathlib. Cheating on a definition has far more serious consequences than cheating on a proof -- indeed IIRC someone once posted an example where if you cheated on a definition then you got a proof for free, which isn't ideal because then when someone fills in the actual definition, the proof breaks.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:29):

@Brandon B I am hoping that once we have a ton of meaty definitions, e.g. in algebraic geometry, then there will be a lot of scope for stating interesting theorems and skipping proofs (not in mathlib, but in another place where one is concentrating on e.g. making search for mathematicians)

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:31):

Unfortunately, there are a bunch of interesting theorems in mathematics about etale cohomology of Noetherian schemes, and it is going to take a whole bunch of category theory to even define etale cohomology. Maybe one cheap definition uses derived functors on an abelian category, but we don't even have abelian categories yet.

view this post on Zulip Mario Carneiro (Apr 12 2020 at 11:33):

So in more serious mathematics this phenomenon shows up a lot -- I would say it's more the rule than the exception. But the point remains that at the level I'm talking about we cannot currently state the results we are interested in because we don't have the definitions in mathlib.

Right, I certainly get the impression that deep theorems abound in higher mathematics, but most of these theorems are not in an accessible place from the point of view of definitions. You spent a bunch of time and effort on perfectoid spaces -- can we state the tilting lemma now? Can we prove basic (and I mean really basic) properties about perfectoid spaces?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:34):

We can't state Scholze's tilting theorem yet because we still need a load more machinery.

view this post on Zulip Mario Carneiro (Apr 12 2020 at 11:35):

Do you know any place where we would get a lot of mileage out of assuming a hard theorem that we can state today?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:35):

This might sound like a stupid thing to say, but I'm not sure there are any basic theorems about perfectoid spaces. I know that in UG maths you make a new object e.g. a ring, and then all of a sudden you can ask if the product of rings is a ring or whatever, but life is not like that on the mountains.

view this post on Zulip Mario Carneiro (Apr 12 2020 at 11:36):

I can imagine that something like that could unlock complex analysis

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:36):

Mario Carneiro said:

Do you know any place where we would get a lot of mileage out of assuming a hard theorem that we can state today?

No. FLT is useless.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:36):

For complex analysis there is still the issue of figuring out what we're going to integrate around and I would imagine that we'd need a bunch of API for whatever it turns out to be before we can get going

view this post on Zulip Filip Szczepański (Apr 12 2020 at 11:48):

not_succ_le_self in the NNG mentions conv begin, but I'm not sure how one would actually use it. My solution ended up just doing a simple induction on a and is only seven lines, and I don't see where conv could be slotted in

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:49):

Oh that's great. I can quite believe that my solutions aren't optimal.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 11:50):

The conv thing is just a very poorly-explained description of how to rewrite on only one side of an expression.

view this post on Zulip Filip Szczepański (Apr 12 2020 at 12:17):

It doesn't seem like either of the solutions for it in the NNG repo uses conv either

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 12:18):

I thought I just checked that the "official" one (in src/game) did

view this post on Zulip Filip Szczepański (Apr 12 2020 at 12:30):

Ah, right, I was looking at the old ones

view this post on Zulip Filip Szczepański (Apr 12 2020 at 12:30):

My solution ended up just being

intro h,
cases h with c h,
induction a with a ha,
  rw succ_add at h,
  exact zero_ne_succ _ h,

  rw succ_add at h,
  exact ha(succ_inj h),

view this post on Zulip Filip Szczepański (Apr 12 2020 at 12:32):

I think my job just ended up being a lot easier because I did the cases before the induction instead of after?

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 13:01):

Any idea why this doesn't work?

example : ((p ∨ q) → r) ↔ (p → r) ∧ (q → r) := iff.intro
    (assume h : (p ∨ q) → r,

        have f1 : p → r, from
            assume h1 : p,
            h (or.intro_left q h1),
        have f2 : q → r, from
            assume h1 : q,
            h (or.intro_right p h1),
        and.intro f1 f2,
    )

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 13:02):

I get error message

type mismatch at application
  prod.mk _
term
  λ (h : p ∨ q → r),
    have f1 : p → r, from λ (h1 : p), h (or.intro_left q h1),
    have f2 : q → r, from λ (h1 : q), h (or.intro_right p h1),
    ⟨f1, f2⟩
has type
  (p ∨ q → r) → (p → r) ∧ (q → r) : Prop
but is expected to have type
  ?m_1 : Type ?
Additional information:
c:\Users\Victor\Desktop\LeanMath\my_project\src\test.lean:139:4: context: switched to simple application elaboration procedure because failed to use expected type to elaborate it, error message
  type mismatch, term
    (?m_3, ?m_4)
  has type
    ?m_1 × ?m_2 : Type (max ? ?)
  but is expected to have type
    (p ∨ q → r) → (p → r) ∧ (q → r) : Prop

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 13:03):

Nvm just an extra comma.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 13:05):

Commas are a nightmare to track down in this verbose term mode.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 13:06):

Start like this:

example (p q r : Prop) : ((p  q)  r)  (p  r)  (q  r) :=
⟨_, _⟩

and go on from there, you're always in control then.

view this post on Zulip Reid Barton (Apr 12 2020 at 13:07):

I'm surprised you didn't get some kind of parse error

view this post on Zulip Reid Barton (Apr 12 2020 at 13:07):

Is (a, ) a tuple section (prod.mk a) or something?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 13:09):

⟨λ h, ⟨λ h1, h $ or.intro_left q h1, _⟩, _⟩

etc

view this post on Zulip Filip Szczepański (Apr 12 2020 at 13:13):

Would it make sense to replace the solutions in the repo with simpler ones where viable?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 13:16):

I don't really ever explicitly link to the repo but I guess there would be no harm in doing so in the future.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 13:27):

Kevin Buzzard said:

Start like this:

example (p q r : Prop) : ((p  q)  r)  (p  r)  (q  r) :=
⟨_, _⟩

and go on from there, you're always in control then.

Looks like a good way to do it. Starting from the bottom.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:08):

Any advice on how to complete:

example : ¬(p ↔ ¬p) :=

without law of the excluded middle?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:09):

congratulations on being the 1000th person to ask this question on the chat :-) Yeah, that's a great question! It's in TPIL right?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:09):

It can be done :-)

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:11):

This was a tough one, I'll have to think a bit more then

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:12):

And yes, it is in TPIL chapter 3

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 15:18):

I once wrote a relatively detailed post on how to prove that one via "chasing underscores". See here to get "spoiled", though it should be written in a way where you can stop and try things out for yourself at each step.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:27):

Might have an idea

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:27):

Is it possible to use other examples you've proved?

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 15:32):

The beginning of that post links to this example. I also apparently did an exercise from Logic & Proof this way.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:35):

Well I don't want any spoilers. I just mean if it is possible in lean to reference a proof you have done earlier as an example.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:37):

The proof I wanted to reference was quite short so I just copied now, but would be good to know for future use.

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 15:39):

Oh, sorry, I misinterpreted "you" in that reply. No, to reference a previous result it has to be a named theorem or lemma or def.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:40):

I see, I guess that's quite logical.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:40):

@Victor Ahlquist there's a canonical hint, if you want it.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:41):

I managed to solve it btw, posting here for anyone interested in my messy solution

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:41):

example : ¬(p ↔ ¬p) :=
    (assume h : p ↔ ¬p,
        have h1 : p → ¬p, from iff.elim_left h,
        have h2 : ¬p → p, from iff.elim_right h,
        have h3 : p → false, from
            (assume f : p,
                h1 f f
            ),
        h3 (h2 h3)
    )

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:41):

Also, I made a video about how I would prove your earlier question ((p ∨ q) → r) ↔ (p → r) ∧ (q → r).

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:42):

Yeah, the hint is "prove not p"

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:42):

Now watch my video and learn how to prove stuff like this without all this assume have stuff :-)

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:42):

Kevin Buzzard said:

Now watch my video and learn how to prove stuff like this without all this assume have stuff :-)

I definitely will :)

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:43):

Just need a minute to wrap my mind around what I just did, felt like a bunch of symbol pushing

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 15:49):

Well, assume is just long-hand for λ. I wouldn't avoid using have, though I'm used to using ":=" instead of ", from".

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:51):

Now that you say it, I remember that the notation in NNG was indeed := not from

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 15:51):

I'm going through TPIL so I'm copying the notation from there.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:53):

TPIL gets on to tactic mode in chapter 5 and for mathematicians tactic mode is far less painful than all this assume stuff.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 15:53):

The natural number game is 100% tactic mode

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 15:59):

Hmm, for some reason I thought the syntax have h, from blah only worked in term mode, but apparently it can be used in tactic mode as well.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 16:01):

Kevin Buzzard said:

TPIL gets on to tactic mode in chapter 5 and for mathematicians tactic mode is far less painful than all this assume stuff.

Yeah tactic mode is nicer for getting an overview of the proof and what needs to be done. I'm still intimated by all the lambda notation in term mode as you might have noticed from my code.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 16:09):

For me writing all the "assume" makes the code more understandable, but I guess that will change as I get more familiar with Lean.

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 16:17):

Now that you've solved it, did you have a look at the "spoiler" posts I linked? Presumably your thought process was not too different from what I described there.

I think it's good that proving simple logical propositions like this feels like symbol pushing. To me it's like getting used to arithmetic or solving algebraic equations in school. Once you're at the stage where these calculations are "just symbol pushing", you can move on to letting a calculator or computer do it for you. In Lean, there are various clever tactics like cc which can solve goals like these automatically.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 16:21):

Ah sorry forgot about the link. Will check it out after dinner.

view this post on Zulip PV (Apr 12 2020 at 16:23):

Thanks for linking those posts. It helped get a better feel for not being in tactic mode, but having the same strategy for building out the proof.

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 16:29):

Yeah, once I learned to read and use the error messages, term mode became a lot less intimidating. I think in principle we could hack Lean to show info in the goal window when putting your cursor in a term mode proof, but that's beyond my abilities. For example, a while back, @Mario Carneiro showed a neat trick where you insert by {}; exact somewhere in a term mode proof and then putting your cursor inside {} shows the context.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 17:05):

That was a nice method with the underscores, will probably come in handy in the future. When I did the problem I noticed that p \r p\r false is the same as p \and p \r false which simplifies to p \r false.

view this post on Zulip Alex Mira (Apr 12 2020 at 17:11):

Hey, this thread is for noob members right? I've spent the last few days playing around with lean, I finished the Nat Num game, and yesterday I downloaded elan to my computer. There's a lotta things I don't understand rn, but currently I'm just wondering how much the base version of Lean knows? It seems to have a \nat type that works well, and an \int type as well but I'm not sure if that one works. It just evaluated 5 - 7 to 0? I've heard there are libraries I could download, but I'd also like the practice of building up to the real numbers myself, if that's possible. Anyway, I'm mostly looking for a place to start, can anyone help me out?

view this post on Zulip Patrick Massot (Apr 12 2020 at 17:15):

Numbers 5 and 7 are interpreted as natural numbers by default, so Lean used nat subtraction which has type nat -> nat -> nat. Then read https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/integer.20subtraction.20.2F.20rational.20division/near/192901989

view this post on Zulip Patrick Massot (Apr 12 2020 at 17:15):

Defining real numbers from core library only is way too ambitious as a beginner goal. But you can play with mathlib real numbers.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:16):

What's your background @Alex Mira ? Maths/CS/other?

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 17:16):

If you haven't already, follow the instructions here for your OS to install leanproject and to set up a Lean project that depends on mathlib.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:17):

Took the words out of my mouth :-)

view this post on Zulip Alex Mira (Apr 12 2020 at 17:18):

Alright, I'll definitely do that then. My background is in math, I'm an undergrad at U of T

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:18):

Core Lean knows basic definitions of e.g. a group. Lean's maths library mathlib knows e.g. the theorems a 1st year undergraduate math group theory course, I think it knows one but not all of Sylow's theorems?

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 17:18):

There are some nice resources under "Learn Lean" on the "Lean Links" page.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:19):

Actually isn't there some link on the docs page where I summarised what mathlib knew last Dec?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:19):

https://leanprover-community.github.io/mathlib_docs/overview.html

view this post on Zulip Alex Mira (Apr 12 2020 at 17:19):

I'm interested though, what Lean calls a Group, it wouldn't technically be the same thing that I think of as a group right? Namely, I'm trying to figure out just how much I can treat Types like they're sets.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:20):

What Lean thinks a group is is absolutely the same as what you think a group is.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:20):

Here's a question for you. Let G be a group. Let g be an element of G. What is g? Is it a set?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:20):

For sure G is a set. But what is g?

view this post on Zulip Patrick Massot (Apr 12 2020 at 17:20):

This is a natural feeling. You simply need to unlearn the lie that people told you you are using set theory.

view this post on Zulip Alex Mira (Apr 12 2020 at 17:20):

Heh, I figured the answer would be something like that.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:21):

If you set up mathematics in ZFC set theory then everything is a set. This is great for G, which you really want to be a set, but it is not great for g, because you want g to be an "atom" of some kind.

view this post on Zulip Patrick Massot (Apr 12 2020 at 17:21):

Type theory is exactly maths the way you think about them, except that you are very good at inserting inclusion maps and isomorphisms, and computer are not quite there yet (but they try really hard).

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:21):

In Type theory, G is a Type, and g is a term. They're different things. g doesn't have elements or anything -- it doesn't even make sense to ask what is inside g. g is an atom.

view this post on Zulip Kenny Lau (Apr 12 2020 at 17:21):

I can imagine a parallel universe where one needs to instead unlearn the lie that we are using type theory; my question is, then what are we using that is somehow an abstracted version of type theory and set theory? or is the foundation separate from the maths?

view this post on Zulip Patrick Massot (Apr 12 2020 at 17:22):

And now is dinner time, so I'll let the IC team continue this explanation.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:22):

I think you're absolutely right Kenny -- I don't think Gauss was using either type theory or set theory

view this post on Zulip Kenny Lau (Apr 12 2020 at 17:22):

so all this nonsense about foundations and two solutions to Russell's Paradox -- what is the point?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:22):

@Alex Mira which U of T? There are several :-)

view this post on Zulip Alex Mira (Apr 12 2020 at 17:22):

Toronto

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:23):

Russell's Paradox has a profound effect on foundations but a mathematician like Poincare will have heard about it and will have realised that it did not affect him in any way whatsoever

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:24):

The problem with Lean's type theory, as far as mathematicians are concerned, is that if G and H are different types, then there can be no term x of type G and of type H: distinct types are disjoint by definition.

view this post on Zulip Alex Mira (Apr 12 2020 at 17:24):

Alright, sounds like my goal rn is to set up a Lean Project, and from there...what are some good goals to set myself if I want to get familiar with the software?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:25):

You could try working on some undergrad problems, that's how I learnt Lean

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:25):

Try proving that the composite of two injective functions is injective.

view this post on Zulip Kenny Lau (Apr 12 2020 at 17:26):

just like how you would learn a natural language: you pick it up by using / reading it a lot

view this post on Zulip Kenny Lau (Apr 12 2020 at 17:26):

and asking us a lot of questions

view this post on Zulip Kenny Lau (Apr 12 2020 at 17:27):

with MWEs (Minimal Working Examples)

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:27):

variables {X Y Z : Type}

def injective (f : X  Y) :=  a b : X, f a = f b  a = b

lemma injective_comp :  (f : X  Y) (g : Y  Z),
  injective f  injective g  injective (g  f) :=
begin
  sorry
end

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:27):

Note I write a b : X instead of a,bXa,b\in X because I'm using the type theory conventions. a : X means "a is a term of type X" which is just the type theory way of saying "a is an element of the set X"

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 17:28):

I think people often work through Theorem Proving in Lean next. The "Hitchhiker's Guide" is a new book that I like too.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:28):

And now you can forget that you're doing type theory and just think of it all in set theory because at this sort of level they are the same theory.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:28):

TPIL is a great way to find out more about type theory in this context.

view this post on Zulip Alex Mira (Apr 12 2020 at 17:28):

Heh, I already did that, and the surjective one. Those were the challenges that didn't require imports I think. Thanks so much!

view this post on Zulip Alex Mira (Apr 12 2020 at 17:28):

TPIL?

view this post on Zulip Alex Mira (Apr 12 2020 at 17:29):

Oh

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:29):

I am always in more of a hurry to recommend it to CS people than maths people.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:29):

Do you know Florian Herzig Alex?

view this post on Zulip Alex Mira (Apr 12 2020 at 17:29):

I do! I'm in his Algebra class!

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 17:29):

We're still waiting on Kevin to write his book on Lean for Generic Mathematicians... :joy:

view this post on Zulip Kenny Lau (Apr 12 2020 at 17:29):

you might not be able to build the theory of real numbers completely; but you'll be sure to learn a lot on the way

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:30):

Yeah, I'm still working on it.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:30):

Books are so 20th century though :-/

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:30):

Florian works in the same area as me.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:31):

Part of the reason he has tenure at UT is that I wrote him a nice reference letter :-)

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 17:31):

I think you can still call it a book even if it has a bunch of interactive bells and whistles.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:40):

@Alex Mira if you have got leanproject working on your computer then you can clone the group theory game and open it in VS Code and then fill in the sorrys in src/group/level01.lean

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:40):

This is a work in progress

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:42):

leanproject get ImperialCollegeLondon/group-theory-game

and then in VS Code go to "open folder" and then open the group-theory-game folder which just appeared in the directory where you were when you ran leanproject.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 17:44):

It's really hard to get started with the group theory game, because I only give you the minimal axioms needed for a group. Proving mul_one and mul_right_inv is a bit of a challenge. Then it gets much easier.

view this post on Zulip Alex Mira (Apr 12 2020 at 17:46):

Sounds fun! Ill definitely try it out.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 18:38):

Is there a tactic that applies a function to both sides of an equality?

view this post on Zulip Kenny Lau (Apr 12 2020 at 18:41):

replace h := congr_arg f h

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 18:44):

thanks

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 18:48):

This is something which mathematicians frequently want to do -- did @Patrick Massot ever write a tactic to do this?

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 18:49):

https://leanprover-community.github.io/mathlib_docs/tactics.html#apply_fun

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 18:50):

apply_fun f at h is a better answer to this question nowadays. It feels more natural.

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 18:51):

We should have a tactic named have_fun.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:01):

Kevin Buzzard said:

apply_fun f at h is a better answer to this question nowadays. It feels more natural.

Yeah it does. Now the second problem is: How do I make a function

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:02):

I guess I shouldn't start defining things carelessly. I just want a function that multiplies by an element from left/right in the group theory game.

view this post on Zulip Kenny Lau (Apr 12 2020 at 19:02):

wait, what is the group theory game?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:02):

it doesn't exist yet

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:03):

https://github.com/ImperialCollegeLondon/group-theory-game

view this post on Zulip Kenny Lau (Apr 12 2020 at 19:04):

multiplication on the left by g is ((*)g)

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:04):

apply_fun (λ x, g * x) at h,

view this post on Zulip Kenny Lau (Apr 12 2020 at 19:04):

multiplication on the right by g is (*g)

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:04):

the power of lambda.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:06):

Thanks, I'll try to learn to handle the lambdas

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:07):

λ x, y just means xyx\mapsto y

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:07):

It's a way of defining a function without giving it a name

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:07):

Yeah I know, I'm just not used to the notation. Chapter 2 of TPIL had a lot of lambda functions

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:08):

Is it possible to use the apply_fun to a goal?

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:08):

no

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:08):

If I had to prove x=y and I was allowed to multiply both sides by 0, I'd be in very good shape

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:09):

Haha that's true.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:09):

Hmm but wait that wouldn't work anyway.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:09):

Your question is "if f(x)=f(y) then does x=y?"

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:09):

and the answer is "only if f is injective"

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:10):

applying it a hypothesis, the question is "if x = y, does f(x)=f(y)" which is a rather different question

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:11):

Ah right.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:13):

Changing the goal is working backwards.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:13):

But wait

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:14):

If your goal is f x = f y you can change it to x = y with apply congr_arg

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:14):

Say I had goal a *1 = a 1, and for some reason I do not use refl immediately. Then wouldn't it be possible to do something like apply apply_fun (\lambda x. ax), to get 1=1 instead

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:14):

Yeah that's what I want

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:15):

No, because apply_fun does not work on goals.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:15):

The fact that it is logically sometimes true doesn't mean that the tactic will ever work.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:15):

Yea happly_fun was a placeholder for another similar function

view this post on Zulip Kenny Lau (Apr 12 2020 at 19:15):

Kevin Buzzard said:

If your goal is f x = f y you can change it to x = y with apply congr_arg

congr' 1

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:15):

Right

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:16):

You have to write `a * 1` or else Zulip thinks you're trying to put something in italics.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:16):

Ah ok

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:17):

You can't get from a * x = a * y to x = y because a could be 0.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:17):

Not in a group

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:18):

Sure

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:18):

Can you prove it in a group though?

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:18):

Do I specify the function after congr_arg?

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:18):

Kevin Buzzard said:

Can you prove it in a group though?

Yep just did :)

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:18):

#check @congr_arg to see what you have to specify

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:19):

Doing the mul_one now, which is why I asked the above question. Then I realized I would need mul_one to use that tactic but still good to know the answer.

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 19:19):

Kevin Buzzard said:

#check @congr_arg to see what you have to specify

Thanks

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 19:37):

apply is a clever tactic. It unifies the conclusion of what you're applying with the goal and then solves the corresponding puzzle

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 20:04):

That was a short and sweet game :)

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:05):

It's not finished yet :-)

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:05):

So here's something I don't know how to do

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 20:05):

Kevin Buzzard said:

apply is a clever tactic. It unifies the conclusion of what you're applying with the goal and then solves the corresponding puzzle

I usually like apply, but now I managed without using it a single time

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:06):

In the natural number game, you prove add_left_cancel and add_assoc and add_comm and you tag them all with simp and then you can prove (a+(b+(c+d)))=(d+b)+(c+a)(a+(b+(c+d)))=(d+b)+(c+a) by simp

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:06):

I am a bit unclear about what the analogous story is for groups

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:06):

and I am even more unclear about what the story is for proving implications

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:06):

i.e. gh=gk    h=kgh=gk\implies h=k

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:07):

My gut feeling is that you should prove a few of them and then let AI take over

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:07):

but the analogous story for rings is the theory of Groebner bases

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:08):

There was a discussion here

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:09):

but I knew a bit less about confluent rewrites back then

view this post on Zulip Reid Barton (Apr 12 2020 at 20:09):

Groebner bases are for commutative rings. For groups this is the word problem, and it is undecidable in general.

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:10):

For implications it's simpler than that

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:11):

https://www3.nd.edu/~andyp/notes/OneRelator.pdf

view this post on Zulip Reid Barton (Apr 12 2020 at 20:12):

The statement forall G (a b c ... z : G), eqn1 -> eqn2 -> ... -> eqnN is the same as asking whether eqnN holds in the free group presented by the assumptions.

view this post on Zulip Reid Barton (Apr 12 2020 at 20:12):

Okay yes, for a single assumption

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:12):

The non-obvious thing we ran into was a * b * c * d = 1 -> d * a * b * c = 1

view this post on Zulip Kevin Buzzard (Apr 12 2020 at 20:14):

Patrick's group tactic seems to use a finite list of theorems

view this post on Zulip Kenny Lau (Apr 12 2020 at 20:15):

can Section 3 (the solution to the word problem for one-relator groups) be formalized (easily)?

view this post on Zulip Victor Ahlquist (Apr 12 2020 at 20:16):

Kevin Buzzard said:

The non-obvious thing we ran into was a * b * c * d = 1 -> d * a * b * c = 1

Non-trivial for a computer to solve?

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 20:24):

can Section 3 (the solution to the word problem for one-relator groups) be formalized (easily)?

How do we express "the word problem is solvable" in Lean? Theorem 2.1 looks like a good first target in any case.

view this post on Zulip Kenny Lau (Apr 12 2020 at 20:30):

decidable_eq

view this post on Zulip Jalex Stark (Apr 12 2020 at 22:29):

what's the name of the obvious term of type inhabited \a \to \a ?

view this post on Zulip Reid Barton (Apr 12 2020 at 22:31):

you should find it either by jump-to-definition to inhabited and look nearby, or inhabited.<completion>

view this post on Zulip Jalex Stark (Apr 12 2020 at 22:33):

Thanks for the advice! I think the term is default
oh, more accurate is that if q: inhabited \a then q.default:\a

view this post on Zulip Mario Carneiro (Apr 12 2020 at 23:35):

Bryan Gin-ge Chen said:

Hmm, for some reason I thought the syntax have h, from blah only worked in term mode, but apparently it can be used in tactic mode as well.

This is due to some clever tricks in tactic parsing. have allows you to omit any of its pieces and it makes a subgoal if you skip the proof of the have, so have h : foo, will make a subgoal proving |- foo, and have h, will make a subgoal proving ?m_1. The comma splits this into two tactics, and the second part is from blah, so from needs to be a tactic. So I made it an alias for exact, and then from blah will make blah the proof of ?m_1 and then the type gets determined and everything else works out.

view this post on Zulip Bryan Gin-ge Chen (Apr 12 2020 at 23:44):

That's great! Thanks for the explanation.

view this post on Zulip Mario Carneiro (Apr 12 2020 at 23:45):

I try to only use from after have, but it's one character shorter and I sometimes see Kenny using it for code golfing :)

view this post on Zulip Reid Barton (Apr 12 2020 at 23:52):

In French you could save two more characters

view this post on Zulip Mario Carneiro (Apr 12 2020 at 23:57):

Are we going to localize lean then?

view this post on Zulip Mario Carneiro (Apr 12 2020 at 23:58):

I never really understood why non-english programmers were content to just use english programming languages

view this post on Zulip Andrew Ashworth (Apr 13 2020 at 00:05):

unicode support is still terrible in lots of mainstream languages

view this post on Zulip Andrew Ashworth (Apr 13 2020 at 00:06):

documentation tends to be written in english, it makes it easier to search stackoverflow if you use english terminology

view this post on Zulip Andrew Ashworth (Apr 13 2020 at 00:07):

for a lot of domain-specific software technology, there is no translation of the terminology

view this post on Zulip Scott Morrison (Apr 13 2020 at 00:51):

Victor Ahlquist said:

I managed to solve it btw, posting here for anyone interested in my messy solution

Here's a cute proof, observing that tidy can follow the hint:

example (p : Prop) : ¬(p  ¬p) :=
λ h, by { have : ¬p, tidy, }

view this post on Zulip Chris M (Apr 13 2020 at 06:30):

How do we do syntax highlighting for Lean in zulipchat? I've tried triple grave accent followed by lean, but it doesn't work?

axiom test : \forallx, x=x

edit: ok it only didn't work in "Drafts"

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 15:24):

(deleted)

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 16:39):

def prime (n : ℕ) : Prop :=  n > 1 ∧ (∀ (k : ℕ), k ∣ n → (k = 1) ∨ (k = n))

def infinitely_many_primes : Prop := (∀ (n : ℕ), ∃ (prime p), p > n))

I'm trying to define "infinitely many primes" but this gets a ton of errors. Not sure if any of it is right.

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 16:39):

Errors at 2nd line, first is ok.

view this post on Zulip Jason KY. (Apr 13 2020 at 16:42):

Would this work for you?

def prime (n : ) : Prop :=  n > 1  ( (k : ), k  n  (k = 1)  (k = n))

def infinitely_many_primes : Prop :=( (n : ),  p : , p > n  prime p)

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 16:43):

Thanks that looks much better. Now I understand what Lean meant by "prime is not a type"

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 17:06):

Which of these ways of writing is preferable in Lean?

def goldbach_conjecture : Prop := ∀ (n : ℕ), even n ∧ n > 2 →  ∃ (p1 p2 : ℕ), prime p1 ∧ prime p2 ∧ n = p1 + p2
def goldbach_conjecture : Prop := ∀ (n : ℕ),  ∃ (p1 p2 : ℕ), even n ∧ n > 2 → prime p1 ∧ prime p2 ∧ n = p1 + p2

view this post on Zulip Reid Barton (Apr 13 2020 at 17:13):

The first one seems better but mostly because it's what one actually means to say

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 17:15):

Yes, the first one looks like it will play better with Lean too, but I don't think I've ever seen a statement written like that before.

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 17:15):

Although I guess I haven't seen many formalizations.

view this post on Zulip Bryan Gin-ge Chen (Apr 13 2020 at 17:16):

I think I'd write the first one like this, removing all the :

def goldbach_conjecture : Prop :=
 (n : ), even n  n > 2   (p1 p2 : ) (hp1 : prime p1) (hp2 : prime p2), n = p1 + p2

view this post on Zulip Victor Ahlquist (Apr 13 2020 at 17:18):

That does look more Leany

view this post on Zulip Reid Barton (Apr 13 2020 at 17:27):

compare https://github.com/leanprover-community/mathlib/blob/master/src/topology/separation.lean#L344 for example

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 17:28):

Are you saying that normal_space could be easier to use if the ands are removed, or are you saying that the way it's done in mathlib is a good idea?

view this post on Zulip Reid Barton (Apr 13 2020 at 17:29):

what would you replace the ands with?

view this post on Zulip Reid Barton (Apr 13 2020 at 17:29):

I'm just saying this is normal Lean code

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 17:30):

exists (u) (v) (hu : is_open u) (hv : is_open v) (hsu : s \sub u) ...

view this post on Zulip Reid Barton (Apr 13 2020 at 17:30):

Also, it really doesn't make much difference whether you pass two hypotheses as an and or separately. This is just style.
The main thing is to put the assumptions and the quantifiers in the right order

view this post on Zulip Reid Barton (Apr 13 2020 at 17:31):

Ah, well, this seems kind of worse but also not important

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 17:31):

..., true

view this post on Zulip Bryan Gin-ge Chen (Apr 13 2020 at 17:31):

I guess we could get everything with rcases either way.

view this post on Zulip Reid Barton (Apr 13 2020 at 17:33):

Or a let, and it will even be the same syntax

view this post on Zulip Bryan Gin-ge Chen (Apr 13 2020 at 17:45):

On the other hand, if we have to prove a goal of the form exists (u) (v) (hu : is_open u) ..., then we can write use [u, v, hu, ...], whereas if it's exists (u) (v), is_open u ∧ ... then it'd be use [u, v, \<hu, ... \>]. Slightly more annoying but not a big deal.

In the case of normal_space, it's more important that it's consistent with all the other separation statements in the file that use ands.

view this post on Zulip Reid Barton (Apr 13 2020 at 17:46):

Ah, I just always use refine, so it makes no difference there as well

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 13 2020 at 19:47):

I've had issues getting various assoc tactics to cooperate. I think I'm misunderstanding something about the way they're supposed to be used. For example, in this proof of zero_add , I want to rewrite the LHS of my goal state so I can apply my inductive hypothesis, but I get an error that Lean couldn't find an instance of the pattern even though I clearly see that the pattern is there. Does it think the k I'm feeding add_assoc is different from the k that's in the goal state?

import data.nat.basic
open nat
theorem zero_add (m : nat) : zero + m = m :=
begin
induction m with k hk,
refl,
rw succ_eq_add_one,
rw  add_assoc 0 k 1,
end

Edit: added the import and open statements before the theorem.
Screen-Shot-2020-04-13-at-3.41.15-PM.png

view this post on Zulip Kenny Lau (Apr 13 2020 at 19:53):

it works for me

view this post on Zulip Kenny Lau (Apr 13 2020 at 19:53):

MWE?

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 19:57):

Just try rw \l add_assoc

view this post on Zulip Kenny Lau (Apr 13 2020 at 19:57):

what I meant is, since this snippet doesn't even compile, that the following works:

theorem zero_add' (m : nat) : nat.zero + m = m :=
begin
induction m with k hk,
refl,
rw nat.succ_eq_add_one,
rw  add_assoc 0 k 1,
end

view this post on Zulip Kenny Lau (Apr 13 2020 at 19:57):

tactic failed, there are unsolved goals
state:
case nat.succ
k : ,
hk : 0 + k = k
 0 + k + 1 = k + 1

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 13 2020 at 20:54):

Kenny Lau said:

what I meant is, since this snippet doesn't even compile, that the following works:

theorem zero_add' (m : nat) : nat.zero + m = m :=
begin
induction m with k hk,
refl,
rw nat.succ_eq_add_one,
rw  add_assoc 0 k 1,
end

Sorry, I should have included the import data.nat.basic and open nat at the beginning. I just added those. This was part of a larger proof and I forgot about those dependencies.

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 20:55):

import data.nat.basic
open nat
theorem zero_add' (m : nat) : zero + m = m :=
begin
induction m with k hk,
refl,
rw succ_eq_add_one,
rw  add_assoc 0 k 1,
rw hk,
end

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 20:56):

This works for me.

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 20:56):

Can you please post a fully working code snippet which shows your problem? So far you have not done this. PS don't edit, just post below.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 13 2020 at 21:08):

I restarted my computer for an unrelated reason and now the issue seems to be resolved. This has happened to me before in Lean and I don't completely understand why.

Anyway here is a working code snippet. I'll repost instead of editing in the future. Thanks for all your help!

import data.nat.basic
open nat
theorem zero_add' (m : nat) : zero + m = m :=
begin
induction m with k hk,
refl,
rw succ_eq_add_one,
rw  add_assoc 0 k 1,
rw hk,
end

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:09):

I have certainly seen weird errors in the past which have been fixed by just quitting VS Code and restarting it again.

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:10):

There are certain errors about memory overflows which really screw Lean up (and probably screw up any computer program). If you get one of those you should probably at the very least restart Lean (with ctrl-shift-P restart Lean)

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:10):

but it continues to function just about normally if you don't.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 13 2020 at 21:13):

These errors were happening in a file of ~500 lines. This file also had a few other unrelated unresolved errors. Could that be a factor?

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:13):

Yes! Your actual problem is the first error in the file.

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:13):

https://xenaproject.wordpress.com/2020/03/24/no-errors/

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 13 2020 at 21:18):

Good to know. I was leaving errors in place so that it would be easier to come back to them if I was working through a long set of problems, but I guess I should stop doing that.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 13 2020 at 21:18):

Sometimes I see students whose file is absolutely full of errors. Their file is 400 lines long, getting really slow, and has 23 errors. They ask me why something doesn’t work, and I know from experience that the answer might be of the form “because something you wrote 100 lines up which caused an error and means that things aren’t the way you think they are”. Some people can get into a real state.

LOL literally me.

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:20):

You are but one of many ;-)

view this post on Zulip Brandon B (Apr 13 2020 at 21:41):

I was reading Kevin Buzzard's recent post "Proofs are not programs" < https://xenaproject.wordpress.com/2019/06/15/proofs-are-not-programs/ > which argues that only in constructive logic is the Curry-Howard correspondence held (proofs are programs) and that in general in ZFC with the axiom of choice and excluded middle etc that Curry-Howard does not apply; which is why is why in lean we label certain things as noncomputable. However, looking at https://en.wikipedia.org/wiki/Lambda-mu_calculus it seems to suggest that there are more sophisticated lambda calculi that can model "classical logic" with excluded middle etc and still maintain a form of the curry-howard correspondence. Is lean's type system CoC just not rich enough to model classical deductions with computational content?

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:46):

I bet they can't model the axiom of choice.

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 21:47):

Lean's system is rich enough to model that -- and that is why I'm still here.

view this post on Zulip Andrew Ashworth (Apr 13 2020 at 22:05):

urgh, if you really want to go into gory detail, you could try chapter 8 of http://disi.unitn.it/~bernardi/RSISE11/Papers/curry-howard.pdf

view this post on Zulip Andrew Ashworth (Apr 13 2020 at 22:07):

but this is written for computer scientists studying type theory

view this post on Zulip Kevin Buzzard (Apr 13 2020 at 22:14):

gaargh it's got those weird fractions in :-/

view this post on Zulip Andrew Ashworth (Apr 13 2020 at 22:18):

that's why I prefixed my statement with "urgh", but maybe I should've added "argh" and "oh no, warning: theoretical computer science"

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:06):

The basic idea behind computational semantics for EM (or more simply, double negation elimination) is that you put everything in continuation passing style, the logical equivalent being putting double negations on everything, and then all the classical theorems become intuitionistically provable, and the computational semantics are that of call/cc or exception handling.

If you wanted to do something similar with full choice, I think you could do it like so: Suppose you want to produce an element of type A satisfying p. Save the current continuation, and then start enumerating well formed terms of type A. Return the first one you find (whether or not it satisfies p). Later, the program may later discover that you lied to it and will prove that the element does not in fact satisfy p, deriving a contradiction. When you call false.elim on this proof of false, the eliminator goes back to the original continuation, "rewinding the universe" to the original state, whereupon it tries the next term it finds.

This should satisfy type correctness, but it is not strongly normalizing as you might be enumerating terms forever looking for one that satisfies p.

view this post on Zulip Marc Huisinga (Apr 13 2020 at 23:06):

as far as i can tell, there's a catch to this lambda-mu-stuff. you won't get "computational content" in the traditional sense, otherwise every proposition would be decidable (in the sense that a TM can output yes/no correctly and halt). so i don't think kevin is wrong here, but you can stretch the definitions a bit to get something that you might call "computational content" again.

as in the link by andrew, the trick is that you enter a special "continuation world" whenever you work with some classical proof that you'd write with LEM or peirce's law. i think mario has described this with time travel before somewhere in this chat, which is quite a cool analogy. the problem is that this "continuation world" does not behave like the normal world in which you program things. for instance, you can't just use LEM, print 0 in the first path and print 1 in the second path, because then you'd have a decider for every proposition.

so now some stuff that i was wondering about, please correct me if it's nonsense.
so when you've got some proof that lives in this continuation world, you need to leave it again so that you can actually observe the results of your program. from what i understand, to do this, you eventually need to construct the object, and if you apply a continuation with your constructed object, the whole chain of continuations unfolds itself.
so in the end, this type of computational content turns these classical proofs into powerful control operators, but to do anything "useful" with them, you eventually need to perform the construction.

i think that there's something similar for choice, but i can't find the paper right now and i didn't understand it well to begin with.

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:09):

You can leave the continuation world fairly simply by applying the CPS converted program to the continuation print

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:09):

You can do so with a proof of em p and it will print p is false

view this post on Zulip Marc Huisinga (Apr 13 2020 at 23:10):

... which is not very helpful

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:11):

It's sort of "false until proven true"

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:12):

It's something like a maximal overestimate of soundness that is still type correct

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:12):

which is to say, it's not sound

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:12):

but it's also not inconsistent

view this post on Zulip Marc Huisinga (Apr 13 2020 at 23:15):

if you want to use the not p you get from em, you need a proof of p. so you apply it to not p and then the program will happily continue on the path where p is true without continuations, right?

view this post on Zulip Marc Huisinga (Apr 13 2020 at 23:37):

would this stuff help with automation in theorem provers?

view this post on Zulip Mario Carneiro (Apr 13 2020 at 23:40):

I know that Cont A is a monad, and this is sometimes used for exception passing in haskell, but for the most part I just see this as a cute trick. It is generally best to say what you mean when programming and these techniques push somewhat in the wrong direction

view this post on Zulip PV (Apr 14 2020 at 01:12):

Are you able to do a "use" like tactic on a premise in this scenario to choose some value for c?
case or.inr
a h : mynat,
hdd : ∃ (c : mynat), a = h + c
⊢ a = h+c

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 01:17):

Where does the c in your goal come from? since it's not in your list of local hypotheses.

Also is hdd is a proof that there is a c such that a = h + c, but you're required to prove that a = h + c for all c

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 01:18):

Also seeing that your goal is mynat, I presume this is the natural numbers game?

view this post on Zulip PV (Apr 14 2020 at 01:18):

yea, i think i may have ended up in a name collision

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 01:19):

Is that the whole goal/tactic state? Even if there was a name collision c should still be there.

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 01:19):

So I guess post your code (and which level it's for)?

view this post on Zulip PV (Apr 14 2020 at 01:23):

code here:
induction b with h hd,
right,
apply zero_le,
left,
apply le_succ,
cases hd with hh hdd,
assumption,
rw le_iff_exists_add at hdd,
rw le_iff_exists_add,
use 0,
symmetry,
simp,

level 9 on inequality world.

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 01:26):

Level 9, so le_total?

I just pasted your code into the Natural Numbers Game, and the tactic state is

a h : mynat,
hdd : ∃ (c : mynat), a = h + c
⊢ a = h

Which is different to what you posted... Also none of your hypotheses are useful here, so you've gone down the wrong path

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 01:27):

Yeah you definitely have, going back up a bit your goal is

case or.inr
a h : mynat,
hdd : h ≤ a
⊢ a ≤ h

view this post on Zulip PV (Apr 14 2020 at 01:29):

ahh thanks

view this post on Zulip Nam (Apr 14 2020 at 04:41):

What is the next step I could try to prove this? i'm reading page 63 of Hitchhiker's Guide but would like to do away with simp.

α : Type,
_inst_1 : inhabited α,
xs_hd : α,
xs_tl : list α,
xs_ih : map (λ (x : α), x) xs_tl = xs_tl
⊢ map (λ (x : α), x) (xs_hd :: xs_tl) = xs_hd :: xs_tl

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 04:42):

I haven't read it, but try unfold map or rw map?

view this post on Zulip Nam (Apr 14 2020 at 04:43):

oh, nice! thank you. they both work. i didn't think of rewrite.

view this post on Zulip Nam (Apr 14 2020 at 04:48):

unfold seems to be better

view this post on Zulip Nam (Apr 14 2020 at 05:04):

now i'm stuck at

view this post on Zulip Nam (Apr 14 2020 at 05:04):

case list.cons
α β : Type,
f : α → β,
ys : list α,
xs_hd : α,
xs_tl : list α,
xs_ih : map f (xs_tl ++ ys) = map f xs_tl ++ map f ys
⊢ map f (xs_hd :: xs_tl ++ ys) = map f (xs_hd :: xs_tl) ++ map f ys

view this post on Zulip Nam (Apr 14 2020 at 05:05):

unfold does not pop xs_hd out of map

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 05:05):

rw map_append?

view this post on Zulip Nam (Apr 14 2020 at 05:06):

map_append is what i want to prove ;)

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 05:06):

Ahh.

view this post on Zulip Nam (Apr 14 2020 at 05:10):

i see. i need to make the input list (xs_hd :: xs_tl ++ ys) into the right form with rewrite list.cons_append, then the unfold works nicely.

view this post on Zulip Shing Tak Lam (Apr 14 2020 at 05:11):

yeah, I was gonna suggest you prove cons_append but I guess using the one provided is fine :)

view this post on Zulip Charley Hutchison (Apr 14 2020 at 06:51):

Are von Neumann algebras (or C^* algebras) a long way from being defined (in terms of how much necessary prerequisite material is implemented, not interest), or could this be done with some concerted effort? I'm not sure whether or not the analysis done so far would is sufficient

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 07:29):

You could ask this in the "is there code for X" stream. Not all the experts read #new members and it's a perfectly respectable question. In general the nontrivial mathematical stuff seems to be stuff put there by mathematicians who work in that area. I don't even remember seeing Hilbert spaces in mathlib, although we have all the ingredients for that.

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 07:29):

My guess is that it would not be hard to define them, given what we have, but that nobody defined them yet

view this post on Zulip Sebastien Gouezel (Apr 14 2020 at 07:35):

I don't think we have anything serious on Hilbert spaces, notably no adjoint operator and no positive operator, so it would be some work (but not too much, I think) to give the usual constructions of concrete C^* algebras (Note that we already have the norm topology and topological stuff, so saying that a set is closed for the norm topology is already there). Doing the abstract theory (complex Banach algebra with a nice involution) would probably be easier, and rather quick.

view this post on Zulip Scott Morrison (Apr 14 2020 at 07:47):

I had a student last year do a lot of the basics (including adjoint operators, I think) on Hilbert spaces, but it never made it to a PR. I think this is all good juicy material for mathlib!

view this post on Zulip Patrick Massot (Apr 14 2020 at 07:59):

I think this is a very good first project.

view this post on Zulip Valentin Vinoles (Apr 14 2020 at 10:02):

If I do the following

variables (E : Type)(G : group E)(H : group E)
variables (x : E)(y : E)
#check x*y

Did * refers to the operation on G or the operation on H?

view this post on Zulip Kenny Lau (Apr 14 2020 at 10:03):

variables (E : Type)(G : group E)(H : group E)
variables (x : E)(y : E)
set_option pp.all true
#check x*y
-- @has_mul.mul.{0} E (@semigroup.to_has_mul.{0} E (@monoid.to_semigroup.{0} E (@group.to_monoid.{0} E H))) x y : E

view this post on Zulip Kenny Lau (Apr 14 2020 at 10:03):

the answer is H

view this post on Zulip Kenny Lau (Apr 14 2020 at 10:03):

the real answer is don't ever do this

view this post on Zulip Valentin Vinoles (Apr 14 2020 at 10:04):

Thank you ! So what should I do if I want to consider two different groups (i.e. two different operations) on the same set ?

view this post on Zulip Kenny Lau (Apr 14 2020 at 10:07):

Are you trying to do Eckmann--Hilton?

view this post on Zulip Kenny Lau (Apr 14 2020 at 10:08):

Johan Commelin said on Sep 07, 2018:

Today I thought it was a good idea to stretch the type class system a bit. In fact, I ended up not using it at all :rolling_on_the_floor_laughing:
https://gist.github.com/jcommelin/2e031b5446ca54089576ea9f66f12abf
Statement: Two unital binary operations that distribute over each other are in fact one and the same. Also, they are commutative and associative, so in fact a monoid structure.
This is used to prove that homotopy groups are abelian.

view this post on Zulip Valentin Vinoles (Apr 14 2020 at 10:10):

Not really, it was just a question because I have troubles to understand exactly how Lean links a group and its operation. I will look for your suggestion, thanks !

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 10:35):

The answer is: (1) if you want to consider a group operation on a type then in Lean you should use square brackets [group E] and not name the group structure at all; (2) 99% of the time you would never consider two different group operations on the same type (which is why [group E] does not say [G : group E]; indeed Lean's type class system (the [] system) is not set up to support more than one instance of a class, and (3) if you do want to do this then you either do it with (G : group E) (H : group E) and then explicitly write stuff like G.mul rather than *, or you define a new type E' := E and you put [group E] and [group E'].

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:27):

Is there a tactic for using lem in tactic mode to check cases?

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:34):

by_cases h : P

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:35):

If you go to the tactic docs and click on "filter by tag" and then select "logic" you will see the sorts of tactic that do this sort of thing.

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:41):

Thanks

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:46):

Is there any danger in using the following?

open_locale classical

view this post on Zulip Kenny Lau (Apr 14 2020 at 19:48):

an army of intuitionistic logicians might send you hate mails

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:48):

Haha I can live with that. Although the command doesn't seem to work

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:49):

Victor Ahlquist said:

Although the command doesn't seem to work

-1 for vague complaint instead of MWE

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:51):

I think the problem is I'm not sure where to use it. At the top?

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:51):

Well, not too near the top :-)

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:52):

There's currently a "feature" of Lean where you can't use it directly after an import. Try using it after any imports and also after a random command like "universe u"

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:52):

open classical
open_locale classical

Gives error invalid namespace name

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:52):

Just delete open classical?

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:52):

Works fine if I remove second row

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:53):

import tactic

noncomputable theory

open_locale classical

is a very mathematician-like way to start a file

view this post on Zulip Reid Barton (Apr 14 2020 at 19:53):

You need to import something from mathlib.

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:53):

Ah I see

view this post on Zulip Kevin Buzzard (Apr 14 2020 at 19:54):

import tactic

/-! hello mum -/

open_locale classical

is another way

view this post on Zulip Victor Ahlquist (Apr 14 2020 at 19:56):

Thanks that solves it. I didn't realize I had to import it. I have all of the exercises in a chapter from TPIL in a giant lean file so I don't mess with the top of it very much.

view this post on Zulip Nam (Apr 14 2020 at 23:03):

what is the most basic way to prove h: 1 = 0 |- false? i'm looking for something like refl, not simp / cc

view this post on Zulip Moses Schönfinkel (Apr 14 2020 at 23:06):

The most basic way in tactic mode (as you've listed tactics) is probably cases h.

view this post on Zulip Nam (Apr 14 2020 at 23:12):

what does it do? i understand that cases break down the term into its inductive constructors

view this post on Zulip Nam (Apr 14 2020 at 23:13):

how does it break down h?

view this post on Zulip Reid Barton (Apr 14 2020 at 23:14):

Fundamentally the way to prove this is to define, by recursion, a function sending 0 to true and succ _ to false, using the hypothesis 1 = 0 to conclude false = true, and using trivial : true to obtain a proof of false

view this post on Zulip Nam (Apr 14 2020 at 23:20):

there is something uneasy about that. the function is custom defined, right? it isn't one that comes from inductive nat : Type, is it?

view this post on Zulip Nam (Apr 14 2020 at 23:20):

or is it one of the axioms that we have to admit?

view this post on Zulip Reid Barton (Apr 14 2020 at 23:22):

I don't understand. You can write it using nat.rec.

view this post on Zulip Nam (Apr 14 2020 at 23:26):

if i "write it", that means the function is defined by me. and it can do anything. how then do we ensure it is logical?

view this post on Zulip Matt Earnshaw (Apr 14 2020 at 23:27):

Nam said:

how does it break down h?

there are no constructors and so the proof is complete

view this post on Zulip Reid Barton (Apr 14 2020 at 23:27):

Why do you not have the same concern about every function you write?

view this post on Zulip Reid Barton (Apr 14 2020 at 23:29):

We're just talking about a perfectly ordinary function, namely

def f :   Prop := λ n, nat.rec_on n true (λ _ _, false)

view this post on Zulip Reid Barton (Apr 14 2020 at 23:32):

nat.rec is an axiom if you like, but if you are suddenly worried about nat.rec, then you should be worried about everything

view this post on Zulip Nam (Apr 14 2020 at 23:34):

no i'm not worry about nat.rec. but i have a bad feeling about f.

view this post on Zulip Reid Barton (Apr 14 2020 at 23:36):

I don't know what to say. Forget all this 0 = 1 business. Do you agree that if someone hands you a natural number, you can inspect it and return one thing if it is 0, and another thing if it is the successor of something? And the first thing could be true, and the second thing false?

view this post on Zulip Nam (Apr 14 2020 at 23:37):

yes, i can do that. at the same time, i can also return true for the first 10 numbers, and false for the rest.

view this post on Zulip Andrew Ashworth (Apr 14 2020 at 23:38):

https://xenaproject.wordpress.com/2018/03/24/no-confusion-over-no_confusion/

view this post on Zulip Andrew Ashworth (Apr 14 2020 at 23:38):

this is the blog post you're looking for

view this post on Zulip Reid Barton (Apr 14 2020 at 23:38):

Is the question, like, why did I choose this particular f?

view this post on Zulip Nam (Apr 14 2020 at 23:55):

yes. sorry i didn't make it clear.

view this post on Zulip Nam (Apr 14 2020 at 23:56):

@Andrew Ashworth thanks for that link. i just finished reading it. there's a lot to take in for a noob like me. but it helped me understand better what @Reid Barton suggested.

view this post on Zulip Brandon B (Apr 15 2020 at 05:23):

True and false are terms of type Prop, but are themselves types? Unlike 1 which is only a term of type \nat ? I guess I don't totally understand what a Prop is in comparison to types like Nat or list

view this post on Zulip Kenny Lau (Apr 15 2020 at 05:25):

Prop is a Sort, meaning that types of Prop are also types

view this post on Zulip Kenny Lau (Apr 15 2020 at 05:26):

Type is also a Sort

view this post on Zulip Mario Carneiro (Apr 15 2020 at 05:48):

Prop and Type are universes, which means that the elements of these types are themselves types

view this post on Zulip Brandon B (Apr 15 2020 at 05:52):

oh right, Prop is the lowest universe level and Type is + 1. What's the point of this separation?

view this post on Zulip Mario Carneiro (Apr 15 2020 at 06:02):

Prop behaves differently from Type u in a number of respects

view this post on Zulip Mario Carneiro (Apr 15 2020 at 06:03):

The most important one is that elements of Prop are proof irrelevant, that is, if p : Prop and h1 h2 : p then h1 and h2 are definitionally equal

view this post on Zulip Mario Carneiro (Apr 15 2020 at 06:05):

If you want to talk about both Prop and Type, you can use Sort u, since Prop = Sort 0 and Type u = Sort (u+1)

view this post on Zulip Brandon B (Apr 15 2020 at 19:40):

How do you know if you need to use the law of the excluded middle? In TPIL there are some basic logical theorems some of which are noted to require classical reasoning, but its not obvious to me how one would figure out what kind of axioms one would need to prove it without just trial and error

view this post on Zulip Kevin Buzzard (Apr 15 2020 at 19:51):

This sort of nonsense might be undecidable or something. But I'm only guessing

view this post on Zulip Robin Carlier (Apr 15 2020 at 19:55):

Hey,
So here is a quite noob question: in the category_theory package, all the definitions have those . obviously, as in here:

extends category_struct.{v} obj : Type (max u (v+1)) :=
(id_comp' :  {X Y : obj} (f : hom X Y), 𝟙 X  f = f . obviously)
(comp_id' :  {X Y : obj} (f : hom X Y), f  𝟙 Y = f . obviously)
(assoc'   :  {W X Y Z : obj} (f : hom W X) (g : hom X Y) (h : hom Y Z),
  (f  g)  h = f  (g  h) . obviously)

I just want to understand clearly what's going on with the syntax here: am I right to understand that this mean that, whenever I instanciate a category, it runs an "obviously" on the arguments I give, which I assume tries to kill off the goal if it's "clear" that the argument I'm giving is an identity/associativity/whatever, and leave it as a goal if there are more things to do?

view this post on Zulip Kenny Lau (Apr 15 2020 at 20:03):

intuitionistic 0-th order logic is decidable but not 1-st order logic

view this post on Zulip Kenny Lau (Apr 15 2020 at 20:03):

@Robin Carlier yes

view this post on Zulip Robin Carlier (Apr 15 2020 at 20:05):

Okay, thank you, and so there the obviously tactic is defined to be simply the tidy tactic, the doc is a bit elusive about what it does exactly, is it like a simp but with less algebraic manipulations and more "rewriting/unfolding definitions" kind of moves?

view this post on Zulip Kenny Lau (Apr 15 2020 at 20:07):

/-
The propositional fields of `category` are annotated with the auto_param `obviously`,
which is defined here as a
[`replacer` tactic](https://leanprover-community.github.io/mathlib_docs/commands.html#def_replacer).
We then immediately set up `obviously` to call `tidy`. Later, this can be replaced with more
powerful tactics.
-/
def_replacer obviously
@[obviously] meta def obviously' := tactic.tidy

view this post on Zulip Kenny Lau (Apr 15 2020 at 20:08):

whenever you declare an instance of category, it will try to use by obviously to prove id_comp', and then change the name to id_comp

view this post on Zulip Kevin Buzzard (Apr 15 2020 at 20:11):

The dot here means "if the user supplies the proof then great, but if they don't then try running the obviously tactic

view this post on Zulip Robin Carlier (Apr 15 2020 at 20:12):

Thank you for your explanation!

view this post on Zulip Kevin Buzzard (Apr 15 2020 at 20:12):

[the dot notation in the reference manual] (https://leanprover.github.io/reference/expressions.html#implicit-arguments)

view this post on Zulip Robin Carlier (Apr 15 2020 at 20:14):

Damn I didn't know there was a reference manual! I thought there was only Theorem proving in lean, well thank you for the link.

view this post on Zulip Kevin Buzzard (Apr 15 2020 at 20:14):

These things are quite well hidden!

view this post on Zulip orlando (Apr 15 2020 at 20:16):

Do we have an instance of a category where obviously fail ?

view this post on Zulip Kevin Buzzard (Apr 15 2020 at 20:32):

Obviously often fails -- it just tries a bunch of obvious things. It will fail if you give it a proof which needs an idea, for example an existence proof

view this post on Zulip Jason KY. (Apr 15 2020 at 21:24):

Hi!
I would like to define a function that maps even and odd numbers differently. I thought to use nat.mod_two_eq_zero_or_one n but that doesn't seem to work. How should I go about defining this function?

def nat_func :   
| 0 := 0
| 1 := 1
| (n + 2) :=
begin
  -- I would like to map even n to n and odd n to 3 * n
  cases nat.mod_two_eq_zero_or_one n, --induction tactic failed, recursor 'or.dcases_on' can only eliminate into Prop
  sorry
end

view this post on Zulip Bryan Gin-ge Chen (Apr 15 2020 at 21:26):

I would just use if ... then ... else ..., e.g.:

def collatz_fn (n : ) :  := if (2  n) then n / 2 else 3 * n + 1

view this post on Zulip Jason KY. (Apr 15 2020 at 21:28):

Right, that seems like a reasonable way of doing it!

view this post on Zulip Brandon B (Apr 16 2020 at 10:43):

I’m struggling to prove “not(p iff not(p))” one of the exercises in TPIL. So far I first assumed “p iff not(p)” with the goal to derive false. I tried using “iff.elim_left” on that assumption but everything I try is giving me an error. Any hints?

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:45):

When I was a young man, I used to follow a USENET newsgroup called rec.puzzles

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:46):

And once a month or so, someone would show up and tell us that there were three words in the English language that ended in GRY.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:46):

Two of them were hungry and angry, and the question was: what was the third one.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:47):

And for some reason this question would just repeatedly show up, again and again, despite there being extensive discussions about the question (and also about why it kept coming up!)

view this post on Zulip Johan Commelin (Apr 16 2020 at 10:48):

cat /usr/share/dict/words | grep gry
angry
hungry

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:48):

However one key difference here is that there is no other word in the English language that ends in GRY (or at least no common one)

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:48):

whereas this question is just a darn good question :-)

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:49):

but it has been answered many times before in #new members. However searching for it will just give you spoilers :-(

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:49):

The hint is : prove "not p".

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:49):

Either that or get with the program and use classical logic :P

view this post on Zulip Rob Lewis (Apr 16 2020 at 10:50):

I feel like we should give this question a name and refer to it by that name in TPIL and L&P and wherever else it appears.

view this post on Zulip Rob Lewis (Apr 16 2020 at 10:50):

And in an answer here.

view this post on Zulip Rob Lewis (Apr 16 2020 at 10:50):

So it's easily found with a search.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 10:50):

The epilogue to the USENET story is that newcomers to rec.puzzles became known as nugrys.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 11:11):

https://tinyurl.com/not-piffnotp

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 11:16):

Also, https://www.definitions.net/definition/nugry

view this post on Zulip Robin Carlier (Apr 16 2020 at 13:19):

Is there a way to fix the value of a variable within the same namespace? In text limits.lean there's this chunk of code :

section colim_functor

variables [has_colimits_of_shape J C]

def colim : (J  C)  C :=

If I reopen this namespace and go #check colim it gives me (?M_1 ⥤ ?M_3) ⥤ ?M_3,
I added an instance [has_colimits_of_shape I C] for some I, but I can't manage to get colim I : (I \functor C) \functor C and colim J: (J \functor C) \functor C to work, any idea?

view this post on Zulip Reid Barton (Apr 16 2020 at 13:20):

You need newlines for multiline blocks, and single backticks for inline code.

view this post on Zulip Robin Carlier (Apr 16 2020 at 13:20):

Thank you

view this post on Zulip Reid Barton (Apr 16 2020 at 13:22):

To answer your actual question, if you want the colimit functor for a fixed index category I, the easiest way is to write colim : (I ⥤ C) ⥤ C. The variable I is implicit (since normally you would want to infer it from the functor you're taking the colimit of).

view this post on Zulip Robin Carlier (Apr 16 2020 at 13:24):

Yep, works like a charm, thank you!

view this post on Zulip Reid Barton (Apr 16 2020 at 13:24):

To answer your original question: Fixing the value of a variable within a namespace doesn't make much sense; namespaces are just a way to organize names. Fixing the value of a variable in a section does make some sense, and that's what parameters does. However, I don't think you want to use it here.

view this post on Zulip Robin Carlier (Apr 16 2020 at 13:31):

My original question was ill-formulated yeah, All I wanted to do is get that colim to have the right type, and I think I get the idea: if I want something to have "X type", just tell that to lean with the :and let it infer the rest :D

view this post on Zulip Reid Barton (Apr 16 2020 at 13:32):

Another option is to write @colim which makes all the implicit arguments into explicit ones, but in this case there are a lot of them.

view this post on Zulip Robin Carlier (Apr 16 2020 at 13:34):

Yeah I tried that initially but got lost in the number of arguments

view this post on Zulip Robin Carlier (Apr 16 2020 at 14:38):

Okay one more question: I'm looking around in the category_theory package, and I see the category Cat of all categories has been formalized, but I don't quite get the code nor how to use it. How should I do, for instance, to introduce the category of all u-Small categories for a fixed universe u? Just Cat.{u u}?

view this post on Zulip Robin Carlier (Apr 16 2020 at 14:41):

Cat.{u u} type checks as Type u+1 which is what I want I guess, but will lean recognize its objects as instances of small-category in the right context?

view this post on Zulip Robin Carlier (Apr 16 2020 at 17:22):

Also, I'm completely stuck on the following, which is quite related to my last question: I have a some category C and D, defined as variables {C : Type u} [𝒞 : category.{u} C], idem with D, and I want to define some functor (over C) ⥤ D in wich I need to make use of the fact that the objects of over Cshould be functors A ⥤ C for some category A. Yet when I try to code that, I can get some morphism A ⟶ C and get Aas well, but I can't get lean to be ok with the fact that A should be a category and that the morphism A ⟶ C should be a functor. I tried various stuff like uliftor apply_instance but nothing work. I guess that's because I'm being vague with the exact typing /instance of over C, and I should be able to tell lean that this over category should be taken in Cat, but despite sniffing around in the code I have no idea about how to do this kind of stuff. Any idea?

view this post on Zulip Reid Barton (Apr 16 2020 at 17:22):

As far as I know, no one has ever used Cat for anything.

view this post on Zulip Reid Barton (Apr 16 2020 at 17:24):

I even defined it in a separate project (before it was in mathlib) and then proceeded to not use that for anything. :upside_down:

view this post on Zulip Robin Carlier (Apr 16 2020 at 17:27):

Ok so it's not possible in a "neat" way to do what I want using Cat then? If not, what could be possible options?

view this post on Zulip Reid Barton (Apr 16 2020 at 17:30):

You want to use Cat indeed, but fix it to make the things you want to do neat.

view this post on Zulip Robin Carlier (Apr 16 2020 at 17:34):

So I guess I'll ding into Cat and see what I can do with that then, thank you!

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 17:35):

disclaimer: I am not a category theorist. I would imagine that Cat is not a category but rather some kind of 2-category. Presumably in Lean one would stick to the category of categories whose objects were in Type u and whose morphism types were all in Type v for some fixed u and v? As for what you're stuck on, I would really encourage you to post some fully working code, because then people like me will just tinker a bit and try and be helpful. [in particular I don't know what over C is but if you give me a file with the right imports at the top I will just be able to look; whilst I am not a category theorist I do know what apply_instance does]

view this post on Zulip Reid Barton (Apr 16 2020 at 17:38):

This will mostly involve things like trying to define coercions, then getting frustrated when they don't work properly.

view this post on Zulip Reid Barton (Apr 16 2020 at 17:39):

But, for sure, in your over example, you would want to start with C : Cat.{u u} and not the unbundled form.

view this post on Zulip Robin Carlier (Apr 16 2020 at 18:08):

@Kevin Buzzard Yeah ideally Cat should be a 2-category, but tbh I don't think I'm up to implementing 2-categories and 2-functoriality and so on yet :D
(Also I'm not a category theorist as well)
I'll look around for defining coercions with cat.
As for some code example, this looks like this so far, feel free to tinker:

import category_theory.limits.shapes
import category_theory.category.Cat
import category_theory.comma
import category_theory.concrete_category.bundled
open category_theory category_theory.category category_theory.limits

universes v u
variables {C : Type u} [𝒞 : category.{u} C]

include 𝒞

namespace colim_functor
  variables [has_colimits.{u} C]
  #check (bundled.of C : Cat.{u u})
  #check over.{u} C
  /- #check over (C : Cat.{u u}) : fails-/
  def colimit_functor : (over C)  C :=
    { obj :=
      begin
        intro a,
        have morph := a.hom,
        tidy,
        have test := (over.forget).obj morph,
        have test2 := test  C, apply_instance,  /- Error here, can't get test to be a category -/

      end,
      map := sorry,
    }

end colim_functor

Anyway thanks @Reid Barton for the advice

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 18:28):

I don't understand the maths at all, but test isn't typechecking. because (over.forget).obj is a function over ? -> ? and you're giving it morph which has type a.left -> C. You could give it a instead, which would make test a term of type Type u. What do you expect the type of test to be? At the moment it's not even defined.

view this post on Zulip Robin Carlier (Apr 16 2020 at 18:34):

Yeah right that's bogus, I don't know why I changed with morph, but I had initially tried with a.
So yeah with ait gives Type u, that much is expected, but I wanted lean to get that this Type u should actually be a Type u with a category instance. So that the functor notation on the line after work
Also there it is test but really this could have been a.left (they're supposed to be the same), but the problem remains if I change test with a.left

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 18:35):

If you want Type u to be a category I think you will need an import

view this post on Zulip Jeremy Avigad (Apr 16 2020 at 18:36):

"hangry": https://www.foxnews.com/food-drink/hangry-is-officially-a-word-in-the-oxford-english-dictionary

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 18:36):

rofl

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 18:38):

The import category_theory.types makes Type u into a category -- but it's a large category.

view this post on Zulip Jeremy Avigad (Apr 16 2020 at 18:40):

Harry Potter fans will have no trouble coming up with a word that starts with GRY.

view this post on Zulip Robin Carlier (Apr 16 2020 at 18:40):

My main issue there is that morph has type a.left \hom C (and not just \l), and that C is a category, so that the information that a.left is a category ought to be already there, otherwise that \hom in the description of a would not type check, see what I mean?
Thanks for the import suggestion tho, I'll try to see if I can get something within types.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 18:48):

morph has type a.left \hom C so a.left must be an object of some category. Looking at the type of morph with set_option pp.all true I can see category_theory.types so you must be importing it somewhere already.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 18:49):

This morphism morph looks to me like it is a morphism in the category Type u.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 18:50):

This makes sense -- C : Type u and Type u has a category structure, so C is an object of the category Type u.

view this post on Zulip Robin Carlier (Apr 16 2020 at 18:52):

I see it yeah, this set_option pp.all true is quite handy, didn't know about it :P.

Well, then it just confirms what Reid said: I definitely want to tinker with Cat since C should be an object of the category Cat.{u u}, rather that Type uthank you a lot for your help and your time!

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 19:09):

You defined {C : Type u} so C is a term of type Type u. I have no idea how to work with Cat I'm afraid.

view this post on Zulip Robin Carlier (Apr 16 2020 at 19:14):

Yeah I get that I should change C to something else to get that to work, or at least coerce it into something else. I'll play around with Cat . I think the object I want to work with is ((bundled.of C) : Cat.{u u}) but unfortunately over doesn't seem to like it

view this post on Zulip Robin Allison (Apr 16 2020 at 22:01):

Is this an appropriate forum for asking about proof assistants in extremely broad terms? Like, I'm starting from the idea of "technology to assist with proofs" (mostly informal) and proof assistants just don't even come close to exhausting that category. Nevertheless I imagine proof assistants form an important subset of that technology and in particular address the technical issues you would encounter when asking the broader question.

view this post on Zulip Kevin Buzzard (Apr 16 2020 at 22:09):

People mostly stick to Lean-related stuff here, it is a very focussed chat in fact. But asking something in #general about general proof assistants isn't going to upset anyone I shouldn't think

view this post on Zulip Robin Allison (Apr 16 2020 at 23:04):

Gotcha. I'm probably want to go beyond the scope of just proof assistants, but I might as well test the water there. Thanks.

view this post on Zulip Mario Carneiro (Apr 17 2020 at 00:40):

I always like to read about more general topics in formal methods, and the people subscribed to this chat are not only lean people but also involved in other areas so it's not a bad place to ask these questions.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 17 2020 at 03:36):

I'm getting a rewrite tactic failed, did not find instance of the pattern in the target expression error on this code again. Not sure if I'm doing something wrong or if my compiler is just getting confused (this has happened in the past in large files with lots of errors, but that is not the case here).

import init.data.nat.basic
open nat

theorem rearrange (a b c : ) : a + (b - c) = b + (a - c) :=
begin
rw  add_sub_assoc,
end

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 03:39):

What you're proving isn't necessarily true.

-- a = 0, b = 2, c = 1
#eval 0 + (2 - 1) -- 1
#eval 2 + (0 - 1) -- 2

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 03:41):

If you give the arguments explicitly to add_sub_assoc, so like this,

rw add_sub_assoc a b c,

You get this error

failed to synthesize type class instance for
a b c : ℕ
⊢ add_group ℕ

Which is what I was referring to

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 03:43):

Essentially what this boils down to is that in lean with the nats, 0 - x = 0.

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 03:44):

So you need either that b ≥ c ∧ a ≥ c as a hypothesis (but this rw still won't work, you could probably solve it with omega), or switch to ints.

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 03:46):

So either

import data.nat.basic
       tactic
open nat

theorem rearrange (a b c : )
  (h1 : b  c)
  (h2 : a  c)
: a + (b - c) = b + (a - c) :=
begin
omega,
end

or

import data.int.basic
open int

theorem rearrange (a b c : ) : a + (b - c) = b + (a - c) :=
begin
rw add_sub_assoc,
-- etc...
end

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 17 2020 at 03:57):

I see, that makes sense. I guess I assumed that add_sub_assoc somehow checked that the values made sense on its own but in retrospect that seems unrealistic. I'll read more about how omega works. Is there a way to prove this by using the assumption b ≥ c ∧ a ≥ c directly without switching to ints?

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 04:00):

Yes.

import data.nat.basic
       tactic
open nat

theorem rearrange (a b c : )
  (h1 : b  c)
  (h2 : a  c)
: a + (b - c) = b + (a - c) :=
begin
  rw nat.add_sub_assoc h1,
  rw nat.add_sub_assoc h2,
  rw add_comm,
end

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 04:01):

There are two different add_sub_assocs, the one that you want is nat.add_sub_assoc, not the one from algebra.group

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 04:03):

When you use rw ←add_sub_assoc Lean uses the one from algebra.group and not the one from nat. So in this case you have to tell Lean that you want the one from nat.

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 04:04):

The one from nat has a different type signature, and that is where you provide the fact that b ≥ c.

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 04:06):

import data.nat.basic
       tactic
open nat

#check add_sub_assoc
-- add_sub_assoc : ∀ (a b c : ?M_1), a + b - c = a + (b - c)
#check nat.add_sub_assoc
-- nat.add_sub_assoc : ?M_2 ≤ ?M_1 → ∀ (n : ℕ), n + ?M_1 - ?M_2 = n + (?M_1 - ?M_2)

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 17 2020 at 04:08):

Interesting, I would have expected doing open nat would default to the nat version, but I guess the different type signature means it never actually looks for the one in nat?

view this post on Zulip Mario Carneiro (Apr 17 2020 at 04:09):

open nat does nothing for type inference

view this post on Zulip Mario Carneiro (Apr 17 2020 at 04:10):

actually in this case the issue is that nat.add_sub_assoc is protected

view this post on Zulip Mario Carneiro (Apr 17 2020 at 04:10):

which means that the name has to be qualified even if you open the namespace

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 17 2020 at 04:57):

Gotcha. This helps a lot. Thank you!

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 17 2020 at 04:59):

Unrelated question: I'm getting errors when I try to access certain namespaces even though I think I've imported them correctly. For example

import init.data.nat
import init.data.list.basic
--https://observablehq.com/@bryangingechen/fibonacci-formalized-1-some-sums?collection=@bryangingechen/lean&fbclid=IwAR1UQq-DS6CG403IjSkBQS5n_evm9soXWgq-NKDyuyxB1Myc0J4tXd8xHhc

open nat list
#eval [1,2,3].sum

This gives me an error on the .sum. Similar thing is happening on le_iff_exists_add and when I try to use a use 0, tactic to kill an inequality. Screen-Shot-2020-04-17-at-12.58.33-AM.png

view this post on Zulip Shing Tak Lam (Apr 17 2020 at 05:00):

Delete the inits.

So

import data.nat.basic
import data.list.basic
--https://observablehq.com/@bryangingechen/fibonacci-formalized-1-some-sums?collection=@bryangingechen/lean&fbclid=IwAR1UQq-DS6CG403IjSkBQS5n_evm9soXWgq-NKDyuyxB1Myc0J4tXd8xHhc

open nat list
#eval [1,2,3].sum

view this post on Zulip Nam (Apr 17 2020 at 15:09):

is there a series of proofs that i should start from in mathlib, the very foundational ones?

view this post on Zulip Kevin Buzzard (Apr 17 2020 at 15:13):

What do you mean?

view this post on Zulip Bryan Gin-ge Chen (Apr 17 2020 at 15:17):

You might want to take a look at the core Lean library, which contains all the code which is imported into every Lean file by default. Start with the imports of init.default in order, e.g. init.core, init.logic, until you get bored...

view this post on Zulip Bryan Gin-ge Chen (Apr 17 2020 at 15:21):

I've personally had more fun picking files or even specific defs / theorems that contain math that I'm familiar with and then working backwards, e.g. looking up the definitions / proofs of unfamiliar declarations.

view this post on Zulip Reid Barton (Apr 17 2020 at 15:23):

I suppose it could be worthwhile though to look at the definitions and basic facts about and, or, Exists, sigma, etc. though I don't know whether they're all in one place

view this post on Zulip Orlando Marigliano (Apr 17 2020 at 15:29):

Hi, I just installed Lean on Ubuntu following "the fast way" in https://github.com/leanprover-community/mathlib/blob/master/docs/install/debian.md.
My problem is: import real.data.basics gives me file 'data/real/basics' not found in the LEAN_PATH. How can I fix this?

view this post on Zulip Patrick Massot (Apr 17 2020 at 15:29):

Remove the extra s at the end

view this post on Zulip Patrick Massot (Apr 17 2020 at 15:30):

And use correct order of words

view this post on Zulip Patrick Massot (Apr 17 2020 at 15:30):

import data.real.basic

view this post on Zulip Orlando Marigliano (Apr 17 2020 at 15:30):

import data.real.basic gives me the same error

view this post on Zulip Patrick Massot (Apr 17 2020 at 15:31):

Did you follow instructions all the way to the crucial last line?

view this post on Zulip Patrick Massot (Apr 17 2020 at 15:31):

Which is a link to https://github.com/leanprover-community/mathlib/blob/master/docs/install/project.md

view this post on Zulip Orlando Marigliano (Apr 17 2020 at 15:32):

I did not, going through that page now

view this post on Zulip Patrick Massot (Apr 17 2020 at 15:34):

I think we really need to change all those installation help pages, inserting between every single line: "At the end of this file, you'll need to follow the link".

view this post on Zulip Patrick Massot (Apr 17 2020 at 15:35):

It seems nobody is capable of clicking that link otherwise.

view this post on Zulip Orlando Marigliano (Apr 17 2020 at 15:37):

Following that link indeed solved my problem. Thanks!

view this post on Zulip orlando (Apr 17 2020 at 15:55):

Hey Orlando :grinning_face_with_smiling_eyes:

view this post on Zulip Orlando Marigliano (Apr 17 2020 at 15:58):

Hey other Orlando :))

view this post on Zulip Robin Carlier (Apr 17 2020 at 17:17):

Does the injection tactic and its derivative automatically recognize a function is injective once it has been proved with function.injective?
In category_theory/opposites.lean there's stuff like

lemma has_hom.hom.op_inj {X Y : C} :
  function.injective (has_hom.hom.op : (X  Y)  (op Y  op X)) :=
λ _ _ H, congr_arg has_hom.hom.unop H

and similar lemmas have no @[simp] attribute, will this kind of lemma be detected by injection?

view this post on Zulip Patrick Massot (Apr 17 2020 at 17:18):

No, this has nothing to do with injection.

view this post on Zulip Patrick Massot (Apr 17 2020 at 17:18):

This tactic has no real world analogue, it's very tightly coupled to the CIC foundations

view this post on Zulip Patrick Massot (Apr 17 2020 at 17:20):

I don't think I ever used that injection tactic

view this post on Zulip Robin Carlier (Apr 17 2020 at 17:21):

Me neither, that's why I'm trying to figure out what it does :sweat_smile:

view this post on Zulip Kevin Buzzard (Apr 17 2020 at 17:29):

injection docs. It proves things like nat.zero ≠ nat.succ n because zero and succ are distinct constructors for nat.

view this post on Zulip Patrick Stevens (Apr 17 2020 at 18:49):

I'm scared to see things like "constructors of inductive data types are injections", given that it's inconsistent with excluded middle in Agda (https://coq-club.inria.narkive.com/iDuSeltD/agda-with-the-excluded-middle-is-inconsistent) - but my Lean is not good enough to attempt to show that that construction of False fails in Lean

view this post on Zulip Kevin Buzzard (Apr 17 2020 at 18:52):

injection proves that the constructors are injective. There are no constructors in the definition of I in that link, so the tactic says nothing in this case.

view this post on Zulip Robin Carlier (Apr 17 2020 at 20:11):

I have some quite noob coercion question: I have the following code, which doesn't work :

import category_theory.category.Cat

universes v u
open category_theory

namespace Cat
    instance cat_to_elem_of_Cat {C: Type u} : has_coe (category.{v} C) (Cat.{v u}) := ⟨λ 𝒞, @Cat.of C 𝒞
    variables {X : Type u} [𝒳 : category.{u} X]
    /- #check (X : Cat)
    #check (𝒳 : Cat)
    Both fail-/
end Cat

I think that's because my instance of has_coe have C as an implicit argument, but I can't see how I can remove it? Basically I want to tell lean that whenever there's a type C with a category instance that is typed as `Cat, then it should coerce it with Cat.of, how should I do that? My problem is mainly that there's both the parameter of the type and the instance of category on that type, rather than just the type.

view this post on Zulip Kevin Buzzard (Apr 17 2020 at 20:43):

What happens if you change the v to a u? Lean 3 struggles with universe unification in situations like this

view this post on Zulip Robin Carlier (Apr 17 2020 at 20:47):

If I change the v to a u in (category.{v} C), then it doesn't type check. If I change it also in Cat.{v u}, then it type checks but the problem remains and it won't coerce X

view this post on Zulip Robin Carlier (Apr 17 2020 at 20:53):

Also same if I try to use only one universe uand coerce with (X : Cat.{u u})

view this post on Zulip Robin Carlier (Apr 17 2020 at 21:02):

I think that's because the type from which I want to coerce from is not the right one, what I really want would be the type of "types equippend with an instance of category on the first type" but I don't know how to write it so that it will accept a coercion from X or 𝒳. The type of "types + a category on said type" is basically already what the Cat type is so it's going in circles.

Reid was right when he was talking about "Trying to define coercions and then getting frustrated when they don't work" :sweat_smile:

view this post on Zulip Reid Barton (Apr 17 2020 at 21:25):

I don't really understand what you wrote but I would go the other way. Write X : Cat, then add has_coe_to_sort so that X can also be treated as a type and then add a category instance for this type.

view this post on Zulip Robin Carlier (Apr 17 2020 at 21:26):

Yeah that much I already did. But I wanted to go able to go the other way, so that there wouldn't be Cat.of ... everywhere

view this post on Zulip Reid Barton (Apr 17 2020 at 21:27):

I don't recommend that

view this post on Zulip Reid Barton (Apr 17 2020 at 21:27):

It sounds like you would have a loop

view this post on Zulip Robin Carlier (Apr 17 2020 at 21:28):

I see, then I'll just keep the coe to sort for X : Catand keep writing Cat.ofwhenever needed

view this post on Zulip Reid Barton (Apr 17 2020 at 21:30):

You shouldn't have to write it very often once you get going, since probably there are not that many different ways you produce a category.

view this post on Zulip Reid Barton (Apr 17 2020 at 21:31):

I still wonder whether it would be better if the whole category theory library was written in bundled style (though, ironically, I'm not sure what happens with Cat itself then)

view this post on Zulip Robin Carlier (Apr 17 2020 at 21:37):

:shrug: I'll just get used to however it is

view this post on Zulip Scott Morrison (Apr 18 2020 at 00:07):

It did start off bundled, and I was talked out of it. :-) People like their typeclasses.

view this post on Zulip Scott Morrison (Apr 18 2020 at 00:09):

I think writing C.hom X Y would have been fine instead of X ⟶ Y. (Another notation that would work with fully bundled categories is X ⟶[C] Y.)

view this post on Zulip Reid Barton (Apr 18 2020 at 00:40):

You should be able to keep the existing notation, I think

view this post on Zulip Reid Barton (Apr 18 2020 at 00:41):

With X Y : ↥C

view this post on Zulip Reid Barton (Apr 18 2020 at 00:51):

I didn't realize it was ever bundled (I assume you mean in your pre-mathlib library)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 00:58):

People liked their is_group_hom typeclasses but ultimately changed their minds.

view this post on Zulip Scott Morrison (Apr 18 2020 at 01:11):

Hmm... maybe it is still doable.

view this post on Zulip Reid Barton (Apr 18 2020 at 01:12):

You should be able to use the same arrow for functors, too

view this post on Zulip Reid Barton (Apr 18 2020 at 01:14):

There might be the usual problems with coercions though (do those happen for has_coe_to_sort also? I mainly encounter them with functions)

view this post on Zulip Reid Barton (Apr 18 2020 at 01:15):

Like X : Over Z might not work because C needs to be inferred (maybe not the greatest example as math writes C in the notation anyways)

view this post on Zulip Jalex Stark (Apr 18 2020 at 03:43):

where is calc mode documented? (or maybe I just need to look at an example?)

view this post on Zulip Shing Tak Lam (Apr 18 2020 at 03:50):

https://leanprover.github.io/theorem_proving_in_lean/quantifiers_and_equality.html#calculational-proofs

view this post on Zulip Jalex Stark (Apr 18 2020 at 04:28):

advice on how to close
lemma case_bash (a : ℕ) (ha : a ≤ 4) : a ∈ [0,1,2,3,4] := sorry
?

Oh, it looks like the interval_cases is supposed to do this. I should remind myself how to update mathlib.

view this post on Zulip Johan Commelin (Apr 18 2020 at 05:06):

Jalex Stark said:

where is calc mode documented? (or maybe I just need to look at an example?)

There is also https://github.com/leanprover-community/mathlib/blob/master/docs/extras/calc.md

view this post on Zulip Nam (Apr 18 2020 at 05:17):

I'm trying to reforming the r* relation in Hitchhiker guide.

inductive star {α : Type} : (α -> α -> Prop) -> α -> α -> Prop
| base (r : α -> α -> Prop) (a b : α) : star r a b
| refl (r : α -> α -> Prop) (a : α) : star r a a
| trans {a b c : α} {r : α -> α -> Prop} (star r a b) (star r b c) : star r a c

but it produces error "don't know how to synthesize placeholder".what did i not get right?

view this post on Zulip Nam (Apr 18 2020 at 05:45):

ahh, i think the left side before : must not have the inductive prop that is being defined.

view this post on Zulip Shing Tak Lam (Apr 18 2020 at 06:13):

Johan Commelin said:

Jalex Stark said:

where is calc mode documented? (or maybe I just need to look at an example?)

There is also https://github.com/leanprover-community/mathlib/blob/master/docs/extras/calc.md

Seems like everything else in that folder is in the mathlib docs except the document about calc.

view this post on Zulip Johan Commelin (Apr 18 2020 at 07:10):

@Shing Tak Lam I guess that folder could use some love now that we have the new docs system. (One for of love could be retirement :wink:)

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 07:31):

https://github.com/leanprover-community/doc-gen/pull/18

view this post on Zulip Johan Commelin (Apr 18 2020 at 07:36):

Great! It's on the queue

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 07:36):

haha, bors doesn't run the doc-gen repo (yet?)

view this post on Zulip Gabriel Ebner (Apr 18 2020 at 07:55):

The doc-gen repo runs Gabriel, which is as almost as fast.

view this post on Zulip Robin Carlier (Apr 18 2020 at 07:58):

Is there a way to "rewrite along an equality" purely in term mode? for instance in the following :

import category_theory.isomorphism

universes v u
open category_theory

section
    variables {C : Type u} [𝒞 : category.{v} C]
    variables (a b: C)
    variable P1 : (a = b)
    include 𝒞 P1
    def canonical : (a  b) := by {have i := 𝟙 a, rw  P1, exact i}
end

I use by and tactic mode to get my (a ⟶ b), is there a term mode way to tell lean "take identity and a and replace one of the a by b since they're equal"?

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 08:02):

You can try to use eq.subst (infix notation ), but it's often much more finicky than using rw

view this post on Zulip Robin Carlier (Apr 18 2020 at 08:09):

Yeah I tried to mess around with it but it "failed to compute the motive"
The question was because I have read that it's better to use term mode to define stuff and leave tactic mode for proving stuff, but now I see that for this particular example it's in tactic mode even in mathlib

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 08:31):

You can always reverse-engineer a term mode proof if you really want:

import category_theory.isomorphism

universes v u
open category_theory

section
    variables {C : Type u} [𝒞 : category.{v} C]
    variables (a b: C)
    variable P1 : (a = b)
    include 𝒞 P1
    def canonical : (a  b) := by {have i := 𝟙 a, rw  P1, exact i}

    set_option pp.proofs true
    #print canonical
    #print canonical._proof_1

    def canonical' : (a  b) :=
    (P1  eq.refl (a  a) : (a  a) = (a  b)).mp (𝟙 a)
end

I guess eq.subst doesn't work directly here because a ⟶ b is not a Prop.

edit: golfed a little more

view this post on Zulip Reid Barton (Apr 18 2020 at 12:00):

Two somewhat contradictory pieces of advice:

  1. You shouldn't use rw to construct data like this; it will cause a lot of headaches later.
  2. This canonical already exists in category_theory.eq_to_hom.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 12:11):

Jalex Stark said:

advice on how to close
lemma case_bash (a : ℕ) (ha : a ≤ 4) : a ∈ [0,1,2,3,4] := sorry
?

Oh, it looks like the interval_cases is supposed to do this. I should remind myself how to update mathlib.

Indeed:

lemma case_bash (a : ) (ha : a  4) : a  [0,1,2,3,4] := by interval_cases a; simp

"Case bashing" is a tactic tag at the docs; this sort of thing comes up a lot and it is only relatively recently that Scott sorted it out. Thanks Scott :heart:

Finally, if you have leanproject installed (the documentation covers it; installing might be as simple as something like sudo pip3 install mathlibtools if you already have elan) then leanproject up will update your project if it is either (a) mathlib or (b) contains mathlib as a dependency. Nowadays it is as simple as that, thanks to the amazing new tooling.

view this post on Zulip Robin Carlier (Apr 18 2020 at 12:17):

Yeah @Reid Barton I saw that that canonical was in eq_hom... And is defined with a rw :grinning:
So I ended up using the one in eq_hom anyway, and it beign constructed with rwdid cause a lot of headeaches

view this post on Zulip Paul van Wamelen (Apr 18 2020 at 15:26):

I have the following start to a file:

import ring_theory.unique_factorization_domain

variables {α : Type*}

namespace associates
open unique_factorization_domain associated lattice
variables [integral_domain α] [normalization_domain α] [unique_factorization_domain α] [decidable_eq (associates α)]

local attribute [instance] associated.setoid
-- local attribute [instance] to_gcd_domain

variable p : { a : associates α // irreducible a }

end associates

But I want to use the fact that a unique factorization domain is a gcd domain, so I'd like to add the commented local attribute [instance] to_gcd_domain. But when I do that I get the maximum class-instance resolution depth has been reached error at the variable p line. Am I doing something wrong? Can I fix this somehow?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:30):

[class_instances] (596) ?x_1789 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := @gcd_domain.to_normalization_domain ?x_1792 ?x_1793
[class_instances] (597) ?x_1793 : gcd_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := @to_gcd_domain ?x_1794 ?x_1795 ?x_1796 ?x_1797
[class_instances] (598) ?x_1795 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := _inst_2
failed is_def_eq
[class_instances] (598) ?x_1795 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := int.normalization_domain
failed is_def_eq
[class_instances] (598) ?x_1795 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := @gcd_domain.to_normalization_domain ?x_1798 ?x_1799
[class_instances] (599) ?x_1799 : gcd_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := @to_gcd_domain ?x_1800 ?x_1801 ?x_1802 ?x_1803
[class_instances] (600) ?x_1801 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := _inst_2
failed is_def_eq
[class_instances] (600) ?x_1801 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := int.normalization_domain
failed is_def_eq
[class_instances] (600) ?x_1801 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := @gcd_domain.to_normalization_domain ?x_1804 ?x_1805
[class_instances] (601) ?x_1805 : gcd_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := @to_gcd_domain ?x_1806 ?x_1807 ?x_1808 ?x_1809
[class_instances] (602) ?x_1807 : normalization_domain (@associates α (@ring.to_monoid α (@domain.to_ring α (@integral_domain.to_domain α _inst_1)))) := _inst_2
failed is_def_eq
...

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:32):

gcd_domain extends normalization_domain and gcd_domain.to_normalization_domain is an instance, so when you add your instance you make a loop. This is presumably why

def unique_factorization_domain.to_gcd_domain
  (α : Type*) [normalization_domain α] [unique_factorization_domain α] [decidable_eq (associates α)] :
  gcd_domain α := ...

is a def but not an instance in mathlib.

view this post on Zulip Reid Barton (Apr 18 2020 at 15:35):

Paul van Wamelen said:

variables [integral_domain α] [normalization_domain α] [unique_factorization_domain α] [decidable_eq (associates α)]

normalization_domain extends integral_domain, so you don't want both. That would give you two unrelated ring structures on the type.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:37):

Now the loop is

[class_instances] (106) ?x_319 : normalization_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := _inst_1
failed is_def_eq
[class_instances] (106) ?x_319 : normalization_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := int.normalization_domain
failed is_def_eq
[class_instances] (106) ?x_319 : normalization_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := @gcd_domain.to_normalization_domain ?x_322 ?x_323
[class_instances] (107) ?x_323 : gcd_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := @to_gcd_domain ?x_324 ?x_325 ?x_326 ?x_327
[class_instances] (108) ?x_325 : normalization_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := _inst_1
failed is_def_eq
[class_instances] (108) ?x_325 : normalization_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := int.normalization_domain
failed is_def_eq
[class_instances] (108) ?x_325 : normalization_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := @gcd_domain.to_normalization_domain ?x_328 ?x_329
[class_instances] (109) ?x_329 : gcd_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := @to_gcd_domain ?x_330 ?x_331 ?x_332 ?x_333
[class_instances] (110) ?x_331 : normalization_domain
  (@associates α
     (@ring.to_monoid α
        (@domain.to_ring α (@integral_domain.to_domain α (@normalization_domain.to_integral_domain α _inst_1))))) := _inst_1
failed is_def_eq
...

view this post on Zulip Reid Barton (Apr 18 2020 at 15:38):

It seems like you might as well just ask for a gcd_domain

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:40):

I always wondered what they were for, maybe Paul is about to tell us :-)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:41):

that crackpot CS class :-)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:42):

Didn't we once decide that Z\mathbb{Z} and k[X]k[X] were the only examples?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:43):

and then there was a proposal to change it all to semrings so we could have N\mathbb{N} and N[X]\mathbb{N}[X] as well :-)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 15:45):

https://math.stackexchange.com/questions/2901858/are-there-any-non-orientable-integral-domains

view this post on Zulip Robin Carlier (Apr 18 2020 at 15:53):

And here I am with yet another noob question arising while I'm trying to make something out of Cat :grinning_face_with_smiling_eyes:
What should I usually do when unification blatantly fails, as in :

import category_theory.isomorphism
import category_theory.category.Cat
import category_theory.opposites
universes v u
open category_theory

section
    instance b_cat_to_sort: has_coe_to_sort (Cat.{v u}) :=
    { S := Type u, coe := λ S, S.α }
    variables {C : Type u} [𝒞 : category.{v} C]
    def opfunctor : Cat.{u u}  Cat.{u u} :=
    {
      obj := λ C, Cat.of ((C.α)ᵒᵖ),
      map := λ C D F, functor.op F,
    }
    lemma op_is_involution : (opfunctor  opfunctor : Cat.{u u}  Cat.{u u}) = 𝟭 Cat.{u u} := begin
        apply functor.ext,
    end
end

Here the proof should be straightforward: look at objects, look at morphisms, done, yet functor.ext won't apply despite the goal being precisely of the right form, I'm a bit lost.

view this post on Zulip Reid Barton (Apr 18 2020 at 15:54):

You've fallen into a classic trap. Try jump-to-definition on functor.ext.

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 15:56):

Robin Carlier said:

Yeah Reid Barton I saw that that canonical was in eq_hom... And is defined with a rw :grinning:
So I ended up using the one in eq_hom anyway, and it beign constructed with rwdid cause a lot of headeaches

I'm not familiar with the category theory library, but would it help if we replaced it with a term mode definition like the one I constructed above?

view this post on Zulip Robin Carlier (Apr 18 2020 at 15:57):

jump-to-definition?

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 15:58):

If you're using VS code you can hit F12 when the cursor is in the name you're interested in to open an editor window at its definition, or you can right click and select "Go to definition".

view this post on Zulip Robin Carlier (Apr 18 2020 at 15:59):

Oh, thank you. well I end up in category rather than category_theory? IS that the "classic trap"?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 16:02):

Almost certainly

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 16:02):

category is for computer scientists only

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:03):

Okay, and so how should I call the "right" functor.ext then? category_theory.functor.ext won't work.

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:06):

Alright I found it, just had to rename when I opened the category_theory namespace, is there any other way than renaming?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 16:08):

What did you rename?

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:09):

I renamed functor.ext to something else, so when I apply, I get the thing I want and not that stuff from category

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:09):

open category_theory (renaming functor.ext → functor.extension) And then apply functor.extension works like a charm

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:11):

But was simply wondering if there's another way

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 16:14):

I had almost forgotten that that was even possible. Are you sure that just using the full name doesn't work? It surely should

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:17):

category_theory.functor.ext? yeah it works to, probably mistyped earlier then.

view this post on Zulip Reid Barton (Apr 18 2020 at 16:18):

By the way, in the category theory library we usually refrain from proving equalities of functors like this because it ends up committing you to the eq_to_hom world. However, I don't think it's necessarily a bad idea, and if you want to work in the 1-category Cat seriously, you have to do this.

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:19):

Yeah I tried to avoid that so far but in this particular case (proving the opposite is an auto-equivalence ) it looks like I have to do that

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:20):

@Bryan Gin-ge Chen regarding that definition with rw I seriously don't know, it's in eq_to_hom and as Reid said this is already quite a weird place

view this post on Zulip Reid Barton (Apr 18 2020 at 16:28):

When you define data using eq.subst/rw it becomes quite painful to prove anything about it. eq_to_hom was an effort to systematize that pain.

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:28):

Yeah it saved my butt earlier in the day

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:37):

Also, is there an intermediate step between the default verbosity and set_option pp.all true? My goal is showing some _terms that should be known (had the same stuff earlier), is there a way to make them display in full?

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 16:38):

set_option pp.proofs true might help.

view this post on Zulip Robin Carlier (Apr 18 2020 at 16:41):

Yes, it removes the underscores! Thank you! Also, I have stuff like ?m_1[X] in my goal, which I assume is "some term that depends on X"? is there a way to make them explicit as well? They remain after set_option pp.proofs true

view this post on Zulip Reid Barton (Apr 18 2020 at 16:48):

They are "some term that depends (or rather, may depend) on X" and Lean doesn't know more about them.

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 16:50):

Frequently you get metavariables in goals because Lean was unable to infer some implicit arguments to a term that you used in apply or refine.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 16:52):

If you have multiple goals then you might find that the ?m_1 in one of them is the solution to another one.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 18 2020 at 17:24):

Shing Tak Lam said:

Delete the inits.

So

import data.nat.basic
import data.list.basic
--https://observablehq.com/@bryangingechen/fibonacci-formalized-1-some-sums?collection=@bryangingechen/lean&fbclid=IwAR1UQq-DS6CG403IjSkBQS5n_evm9soXWgq-NKDyuyxB1Myc0J4tXd8xHhc

open nat list
#eval [1,2,3].sum

I tried doing that and got an error that mathlib wasn't in the lean path. Going back to my previous work it looks like I've always been usingimport init.data.nat.basic instead of import data.nat.basic. How do these two differ? How would one give me partial access to some nat stuff if mathlib wasn't in my lean path to begin with?

view this post on Zulip Reid Barton (Apr 18 2020 at 17:25):

Some of the nat stuff is in the core library rather than mathlib, and it happens to be in a module named init.data.nat.basic. But you get this automatically even if you don't import it (that's a feature of core library stuff under init.*).

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 17:26):

I don't see how import init.data.nat.basic could do anything unless you have prelude at the very top of your file.

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 17:31):

Oh, I see. Your file wasn't relying on mathlib at all before. So instead of just removing the inits from the imports, I would just delete the import data.nat.basic and import data.list.basic entirely.

If you do want to use stuff from mathlib, then you'll need to fix the path issue, and the best way to do that is to look at the install docs again, specifically the "project" doc if you've gotten leanproject working.

view this post on Zulip Nam (Apr 18 2020 at 17:40):

i have this

inductive sorted : list  -> Prop
| nil {} : sorted []
| one {x : } : sorted [x]
| other {x y : } {tail : list } (h: x <= y) (hs : sorted (y :: tail)) : sorted (x :: y :: tail)

how do i def a function that takes a sorted list and returns a sorted list?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:41):

id?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:42):

Is there a typo?

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:42):

there are 3 Coq kata, all authored by @Donald Sebastian Leung, asking us to verify his sorting algorithms

view this post on Zulip Nam (Apr 18 2020 at 17:42):

ah, right. sorry. i missed it. i meant to ask for a function that takes an \N, a sorted list, and returns another sorted list.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:43):

Well then you can throw away the natural and return the sorted list.

view this post on Zulip Nam (Apr 18 2020 at 17:43):

(i.e. insertion sort)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:43):

Oh, this function has some hitherto undisclosed properties :-)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:44):

I would imagine that defining this function isn't too hard using the equation compiler.

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:44):

(removed)

view this post on Zulip Reid Barton (Apr 18 2020 at 17:44):

For some reason people on Haskell channels like to ask questions like this, as though it's always obvious what any function would do from its type.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:44):

Actually, you might end up having to ask Chris how to get your recursion to be well-founded.

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:45):

Kevin Buzzard said:

Actually, you might end up having to ask Chris how to get your recursion to be well-founded.

can't you just deconstruct the list one element by one element

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:45):

each time you only need to recurse on the normal thing

view this post on Zulip Nam (Apr 18 2020 at 17:46):

@Kenny Lau i assume your Coq resource was directed to me. how does that help me understand Lean syntax?

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:46):

that was before you clarified that you want insertion sort

view this post on Zulip Nam (Apr 18 2020 at 17:47):

there was some resource in Software Foundations about insertion sort, where my inspiration comes

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:47):

Why not post the Coq code and ask how to translate it?

view this post on Zulip Nam (Apr 18 2020 at 17:47):

the problem i'm having is to find the right incantation

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 17:48):

I don't think the mods will mind Coq code, as long as you don't do it too often.

view this post on Zulip Nam (Apr 18 2020 at 17:48):

i prefer it to be as natural as possible. i'm trying to learn the intuition behind it, not the mechanical translation of Coq -> Lean.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 18 2020 at 17:49):

Bryan Gin-ge Chen said:

Oh, I see. Your file wasn't relying on mathlib at all before. So instead of just removing the inits from the imports, I would just delete the import data.nat.basic and import data.list.basic entirely.

If you do want to use stuff from mathlib, then you'll need to fix the path issue, and the best way to do that is to look at the install docs again, specifically the "project" doc if you've gotten leanproject working.

This seems to be what my problem was - must have built my current project workspace incorrectly. I follow the directions to make a new workspace and now import data.nat.basic doesn't error anymore. Thank you!

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:50):

@Nam have you seen how to recurse on a list?

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:50):

if not, recurse on a natural number?

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:50):

(I'm too busy to type any Lean code)

view this post on Zulip Nam (Apr 18 2020 at 17:51):

no worries! any idea is welcome. yes i know the concepts. what i'm asking isn't the implementation of such function. i'm only asking for the signature of the def.

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:52):

oh that I can write: def insertion_sort : \N \to list \N \to list \N

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:52):

(my algorithm doesn't need the list to be sorted in the first place to work)

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:52):

(but I can guarantee that if you input a sorted list you will get a sorted list)

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:52):

here in Lean we prefer to totalize our functions

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:53):

and then theorem insertion_sort_correct: \forall n L, sorted L \to sorted (insertion_sort n L)

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:53):

or some other properties that you want to verify

view this post on Zulip Nam (Apr 18 2020 at 17:55):

i don't quite understand your insertion_sort. does it sort a list, or does it insert a new element to a sorted list?

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:55):

it insert a new element to a list in the appropriate place

view this post on Zulip Nam (Apr 18 2020 at 17:55):

so then that list must be sorted.

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:55):

such that if the list is sorted to begin with, the output list will be sorted

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:55):

we don't like partial functions

view this post on Zulip Reid Barton (Apr 18 2020 at 17:55):

It should probably be called something more like sorted_insert

view this post on Zulip Reid Barton (Apr 18 2020 at 17:56):

Also, the alternative isn't really a "partial function", it's a function with a precondition

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:56):

I mean, the algorithm is basically: if the new element is smaller than the first element then put it before the first element; otherwise if it is smaller than the second element then put it before the second element, etc

view this post on Zulip Kenny Lau (Apr 18 2020 at 17:56):

none of the processes here requires the list to be sorted

view this post on Zulip Bryan Gin-ge Chen (Apr 18 2020 at 17:57):

I know you're doing this as a learning exercise, but at some point you may find it interesting to compare with the sorting code in mathlib: https://github.com/leanprover-community/mathlib/blob/master/src/data/list/sort.lean

view this post on Zulip Reid Barton (Apr 18 2020 at 17:57):

Nam, how is it written in your Coq book?

view this post on Zulip Nam (Apr 18 2020 at 17:58):

https://softwarefoundations.cis.upenn.edu/vfa-current/Sort.html

view this post on Zulip Reid Barton (Apr 18 2020 at 17:58):

Yes, it's just the same in Lean then.

view this post on Zulip Nam (Apr 18 2020 at 17:59):

yes, my sorted is very similar.

view this post on Zulip Reid Barton (Apr 18 2020 at 17:59):

I mean the syntax is not literally the same, because of the way the equation compiler works.

view this post on Zulip Nam (Apr 18 2020 at 17:59):

but i don't like the idea of feeding my "insert one element" with any list.

view this post on Zulip Reid Barton (Apr 18 2020 at 18:00):

But the separation of program from properties that Kenny is advocating is also in the original Coq version.

view this post on Zulip Nam (Apr 18 2020 at 18:00):

true. that's where i'd like to divert from the book. doing my own thing, if you will ;).

view this post on Zulip Nam (Apr 18 2020 at 18:01):

i think it's okay for the main sort function to take any list, but the insert one element function should only accept sorted list.

view this post on Zulip Reid Barton (Apr 18 2020 at 18:03):

Okay, you can do that by writing def insert : ℕ → Π (l : list ℕ), sorted l → list ℕ

view this post on Zulip Reid Barton (Apr 18 2020 at 18:03):

but if you implement this function, you'll find you never use the sorted l hypothesis

view this post on Zulip Nam (Apr 18 2020 at 18:03):

can i also qualify the output?

view this post on Zulip Nam (Apr 18 2020 at 18:04):

i think that's where this hypothesis will be used

view this post on Zulip Reid Barton (Apr 18 2020 at 18:04):

def insert : ℕ → Π (l : list ℕ), sorted l → {l' : list ℕ // sorted l'}

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:04):

But if you do it like that then you'll have to do your work in the definition

view this post on Zulip Reid Barton (Apr 18 2020 at 18:05):

Now you have completely abandoned "separate program from properties". Sometimes it's easier this way.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:05):

Why not factor things out into the definition everyone else is suggesting

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:05):

And then prove the theorem

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:05):

And then make your definition

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:05):

Which by this point will be one line long

view this post on Zulip Reid Barton (Apr 18 2020 at 18:05):

Well, sometimes you end up repeating work if you prove the properties separately

view this post on Zulip Reid Barton (Apr 18 2020 at 18:06):

Like in this case it might well be easier to prove the property at the same time as making the definition

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:06):

I see

view this post on Zulip Reid Barton (Apr 18 2020 at 18:07):

Of course in this case, it's also easy either way

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:07):

Right

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:07):

But I see the general principle

view this post on Zulip Nam (Apr 18 2020 at 18:07):

i'm a software engineer. this is the natural way i would approach insertion sort.

view this post on Zulip Nam (Apr 18 2020 at 18:07):

but i see your points about "total function" or something like that.

view this post on Zulip Nam (Apr 18 2020 at 18:08):

(of course i don't know what that means yet)

view this post on Zulip Reid Barton (Apr 18 2020 at 18:08):

There are reasons you might prefer one over the other but I wouldn't exclude either approach a priori.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:08):

It means define the function without assuming the import list is sorted -- define it on all lists

view this post on Zulip Kenny Lau (Apr 18 2020 at 18:08):

if you're a software engineer, then you don't prove any properties at all when you build your function, and you would build your function exactly how I suggested: without caring about whether the original list is sorted

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:09):

Like the square root function in mathlib is defined on all real numbers and just returns junk for negative ones

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:09):

Lean offers you a way to prove that your code has no bugs

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:09):

That would be the theorem you'd prove about your total function

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:10):

You would accept the garbage in garbage out principle. Why check the list is sorted? It just wastes time

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:11):

So in the definition you can take any list

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:11):

And then the theorem you prove is that if the list is sorted your function isn't buggy

view this post on Zulip Nam (Apr 18 2020 at 18:12):

thanks! i'll need to adopt that thinking.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:12):

But you don't release the theorem to the customer, you just give them the super fast function and a warning that if they put garbage in they'll get garbage out

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:13):

And if they want to check their input before they give it to your function that's their choice

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:14):

They might instead choose to prove that their code which generates the list they will feed to your function is always sorted

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:14):

And they can put that in the unit tests and not ship it

view this post on Zulip Nam (Apr 18 2020 at 18:21):

my take of dependent type is it helps me ensure some properties at compile time. e.g. sqrt n, n >= 0 ensures that clients cannot pass invalid input throughout the whole program. i like that very much.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:31):

Well you can offer both functions to the customer

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:33):

The one which demands a certificate that the list is sorted costs more to use but has the advantage that it outputs a guarantee that the output is also sorted

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:34):

You shouldn't be writing your own algorithms that check your customer's list is sorted, the customer's lists might have properties which only they know about which might make checking much easier for them than for you

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 18:35):

The compile time win is what you get when you define the more sophisticated function

view this post on Zulip Luca Seemungal (Apr 18 2020 at 20:15):

Question: Given h : ∃ x : α, p x, how do I pull out a term x : α and a term hx : p x where p : α → Prop?

Discussion: In TPIL, it says:

"The existential elimination rule, exists.elim, performs the opposite operation. It allows us to prove a proposition q from ∃ x : α, p x, by showing that q follows from p w for an arbitrary value w. Roughly speaking, since we know there is an x satisfying p x, we can give it a name, say, w. If q does not mention w, then showing that q follows from p w is tantamount to showing the q follows from the existence of any such x."

What has q got to do with anything?

view this post on Zulip Kenny Lau (Apr 18 2020 at 20:17):

well when you say "pull out a term ..." you have a goal in mind, i.e. a proposition you want to prove, and that is q

view this post on Zulip Kenny Lau (Apr 18 2020 at 20:18):

but I would agree that "if q does not mention w" sounds a bit clumsy to me

view this post on Zulip Luca Seemungal (Apr 18 2020 at 20:22):

yeah, the proposition i want to prove is the stuff that is in the goal next to the turnstile, right?

sorry, i'm not sure if i understand. I'm kind of expecting to be at a point where i can have x : α and hx : p x in my assumptions, and I don't know what q has got anything to do with me wanting that

view this post on Zulip Reid Barton (Apr 18 2020 at 20:25):

If you're in tactic mode, then probably the answer you're looking for is cases h with x hx.

view this post on Zulip Reid Barton (Apr 18 2020 at 20:25):

TPIL is explaining the theory behind the term that that tactic will generate.

view this post on Zulip Luca Seemungal (Apr 18 2020 at 20:27):

yes, that tactic worked! I should probably at some point figure out the theory though

view this post on Zulip Luca Seemungal (Apr 18 2020 at 20:27):

cheers

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 20:45):

If h : ∃ x : α, p x is a hypothesis and your goal is ⊢ q then what you are trying to do is to prove (∃ x : α, p x) -> q

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 20:47):

I wouldn't worry about what TPIL says. The authors are thinking about how to explain what is going on to computer scientists who think about logic in some weird way involving gigantic fractions with sideways T's on the numerator and denominator. Mathematicians don't need to think about that because they only use one logic and they have completely internalised it.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 20:48):

You just need to know that clearly if we have proved there exists x such that p(x) then we can obviously just take such an x. Computer scientists might want to think very carefully about what just happened there, but I don't see any reason why mathematicians need to.

view this post on Zulip Nam (Apr 18 2020 at 21:06):

i have h1 : Prop := x ≤ head, how do i turn that into x ≤ head : Prop?

view this post on Zulip Nam (Apr 18 2020 at 21:06):

sorry if that sounds silly

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:07):

How did you make h1 and are you in term mode or tactic mode?

view this post on Zulip Nam (Apr 18 2020 at 21:07):

i've been trying to make Reid's suggestion work.

inductive sorted : list  -> Prop
| nil {} : sorted []
| one {x : } : sorted [x]
| other {x y : } {tail : list } (h: x <= y) (hs : sorted (y :: tail)) : sorted (x :: y :: tail)

lemma tail_of_sorted_list_is_sorted {xs : list } (hs : sorted xs) : sorted (list.tail xs) :=
begin
  induction xs,
  case list.nil { apply sorted.nil },
  case list.cons : head tail {
    rewrite list.tail,
    cases hs,
    case sorted.one { exact sorted.nil },
    case sorted.other : tail_head tail_tail h_lte h_sorted { exact h_sorted }
  },
end

def ins_sort_insert :  -> Π (l: list ), sorted l -> {l' : list  // sorted l'}
| x [] h := [x], sorted.one
| x (head :: tail) h :=
  let h1 := x <= head in
    if h1 then
    begin
      exact  x :: (head :: tail), sorted.other h1 h,
    end
    else
    begin
      exact head :: (ins_sort_insert x tail (tail_of_sorted_list_is_sorted h)), h,
    end

view this post on Zulip Nam (Apr 18 2020 at 21:08):

h1 is created by the let clause

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:08):

Can you post complete working code so I can just cut and paste?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:10):

type mismatch at application
  sorted.other h1
term
  h1
has type
  Prop : Type
but is expected to have type
  x  head : Prop

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:10):

h1 is a proposition; h1 : Prop.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:10):

But the first input to sorted.other isn't something of type Prop, it's a proof

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:11):

Don't confuse a theorem statement and a theorem proof.

view this post on Zulip Nam (Apr 18 2020 at 21:11):

so by h1 then?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:11):

h1 is a type. You don't want to feed in h1, you want to feed in a term of type h1.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:12):

I don't see a proof of h1 in your context, because you used if and not a dependent if.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:12):

You need to do this:

  let h1 := x <= head in
    if h1proof : h1 then

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:13):

This carries the proof of h1 into the then clause

view this post on Zulip Nam (Apr 18 2020 at 21:14):

oh, thanks! that's another incantation for me to remember.

view this post on Zulip Nam (Apr 18 2020 at 21:14):

actually, i don't need h1, i need its proof.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:14):

if c then ... else is syntax sugar for ite:

ite : Π (c : Prop) [h : decidable c] {α : Sort u_1}, α  α  α

and the case split doesn't carry the proof along with it.

view this post on Zulip Nam (Apr 18 2020 at 21:14):

can i do let h1 : (x <= head : Prop) := x <= head in?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:16):

x <= head is a Proposition. It's a term of type Prop. 2+2=5 is a proposition. You can write let h1 := 2 + 2 = 5 in ... and that's fine. You've just defined h1 to be a proposition which is always false.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:16):

No amount of shuffling syntax around is going to come up with a proof of 2+2=5 though.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:16):

Prop is the universe, P : Prop is the type and h : P is the term. h is a proof of P.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:17):

You can make as many P's as you like, but making h's is hard.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:17):

You can't just create a proof that x <= head because it might not be true.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:18):

What you called h1 is not the usual notation for this -- usually h is used for proofs and stuff like p or P is used for the propositions.

view this post on Zulip Nam (Apr 18 2020 at 21:18):

i see. that's why it's only available in the case split.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:18):

Right. In the dependent case split you split into either there being a proof of h1 or a proof of not h1

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:19):

if h : P then ... else ... is syntax sugar for dite:

dite : Π (c : Prop) [h : decidable c] {α : Sort u_1}, (c  α)  (¬c  α)  α

dite is better than ite because you get a proof of c or not c as appropriate when you're trying to construct your terms of type alpha which you need to fill in the inputs to the dite.

view this post on Zulip Nam (Apr 18 2020 at 21:19):

btw, does this look "idiomatic" other than the naming?

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:20):

the begin exact end is superfluous

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:20):

begin exact h end is the same as h

view this post on Zulip Nam (Apr 18 2020 at 21:20):

ah well, i dno't know how many lines i would need, so begin and end

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:20):

the let h1 := x <= head seems very odd but you may have fixed it by now

view this post on Zulip Nam (Apr 18 2020 at 21:21):

i was just going to call it p

view this post on Zulip Nam (Apr 18 2020 at 21:21):

maybe that's not enough?

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:21):

you don't need the let at all

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:21):

if h : x <= head then

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:21):

just use if h : x <= head then ... else ...

view this post on Zulip Nam (Apr 18 2020 at 21:21):

got it.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:22):

wooah you already have an h

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:22):

if h2 : x <= head then

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:25):

def ins_sort_insert :  -> Π (l: list ), sorted l -> {l' : list  // sorted l'}
| x [] h := [x], sorted.one
| x (head :: tail) h :=
  if h2 : x <= head then
   begin
      exact  x :: (head :: tail), sorted.other h2 h,
    end
    else
    begin
      refine head :: (ins_sort_insert x tail (tail_of_sorted_list_is_sorted h)), _⟩,
      sorry -- you have some work to do
    end

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:25):

You can also inline / simplify the proof of tail_of_sorted_list_is_sorted in ins_sort_insert

view this post on Zulip Nam (Apr 18 2020 at 21:26):

i can't use h2 in the else, can i?

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:26):

you can

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:26):

The missing proof (indicated with an _) is not h

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:26):

h2 is a proof of ¬x ≤ head in the else branch

view this post on Zulip Nam (Apr 18 2020 at 21:26):

but h2 won't be accepted by sorted

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:27):

The type of h2 is currently not (le x head)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:27):

and sorted doesn't seem to have any inputs of that type

view this post on Zulip Nam (Apr 18 2020 at 21:27):

should it?

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:27):

no

view this post on Zulip Nam (Apr 18 2020 at 21:27):

sorted seems to be complete. yeah.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:28):

what did you try?

view this post on Zulip Nam (Apr 18 2020 at 21:28):

i've only tried sorted.other h2 h, similar to the if clause.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:28):

code

view this post on Zulip Nam (Apr 18 2020 at 21:28):

else
  begin
    exact head :: (ins_sort_insert x tail (tail_of_sorted_list_is_sorted h)), sorted.other h_x_head h,
  end

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:28):

complete code?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:29):

What is h_x_head? Please post complete code

view this post on Zulip Nam (Apr 18 2020 at 21:29):

def ins_sort_insert :  -> Π (l: list ), sorted l -> {l' : list  // sorted l'}
| x [] h := [x], sorted.one
| x (head :: tail) h :=
  if h_x_head : x <= head then
    x :: (head :: tail), sorted.other h_x_head h
  else
  begin
    exact head :: (ins_sort_insert x tail (tail_of_sorted_list_is_sorted h)), sorted.other h_x_head h,
  end

view this post on Zulip Nam (Apr 18 2020 at 21:29):

it is what i call your h2

view this post on Zulip Nam (Apr 18 2020 at 21:30):

i understand that current code won't work.

view this post on Zulip Nam (Apr 18 2020 at 21:30):

(as Kevin showed before)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:30):

sorted.other needs a proof of A <= B for some A and B, and h_x_head has type not (something) which is not the same as le A B

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:30):

You can see this in the error message. You have to prove a theorem here.

view this post on Zulip Nam (Apr 18 2020 at 21:30):

right, that's what i'm trying to reconcile.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:31):

You should use \not (x <= head) to prove head <= x, using le_of_not_ge, but even then I think it will not work because h isn't the right second argument

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:31):

But you can't just get this for free, it's not just a simple thing, this is where the work is.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:32):

indeed I would be surprised if you can finish the proof from here, because you don't know enough in the inductive hypothesis

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:32):

In fact I am not even sure that your theorem is true

view this post on Zulip Nam (Apr 18 2020 at 21:33):

insert to a sorted list does not yield another sorted list?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:33):

All you know is head < x, but you need that head <= (smallest element of tail) for your list to be sorted

view this post on Zulip Nam (Apr 18 2020 at 21:33):

smallest element of tail is its head

view this post on Zulip Nam (Apr 18 2020 at 21:33):

because tail of a sorted list is sorted

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:33):

Right, but you don't know anything about the head of tail.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:34):

To clarify Kevin's assertion, of course the function is in fact going to sort the list, but you can't just prove that by induction, the induction hypothesis needs to be stronger than that

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:34):

Actually I think we might be OK

view this post on Zulip Nam (Apr 18 2020 at 21:34):

ahhh

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:34):

We have h : sorted (head :: tail)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:35):

so head <= head(tail)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:35):

wait

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:35):

If you had a separate definition, this would be less of a problem because you would know what list is being returned, but here you only know you have some sorted list

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:35):

so who knows if adding head to the front of it keeps it sorted

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:35):

it has no relation to the input

view this post on Zulip Nam (Apr 18 2020 at 21:35):

the input is x

view this post on Zulip Nam (Apr 18 2020 at 21:36):

and x > head

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:36):

That is, you don't know that ins_sort_insert x tail (tail_of_sorted_list_is_sorted h) contains x or tail or has any relation to them. It might be the empty list

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:36):

the only thing the type tells you is that it is a sorted list

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:37):

The problem is that because of your choice of induction, all you know about ins_sort_insert x tail _ is that it is a sorted list.

view this post on Zulip Nam (Apr 18 2020 at 21:37):

ahh. so i need a stronger condition? say, list.length > 0?

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:37):

that assumption won't help you prove the theorem

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:38):

you need something that relates the output to the input

view this post on Zulip Nam (Apr 18 2020 at 21:38):

what have i got into. lol.

view this post on Zulip Nam (Apr 18 2020 at 21:38):

i thought this would be a walk in the park ;)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:38):

theorem proving :-)

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:38):

Did you prove that the reverse of the reverse of a list was itself yet?

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:38):

That was the point where I realised that lists were harder than they looked.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:39):

That theorem is delicate in the same way that this is delicate.

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:39):

Mario can probably write some incomprehensible 5-line definition which works fine

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:39):

lol

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:39):

but what I learnt very early on is that just because it can be done in 5 lines of code, doesn't mean at all that it is easy to do in 5 lines of code.

view this post on Zulip Nam (Apr 18 2020 at 21:40):

not so sure if i've done that. i started with Hitchhiker's guide, and it solved that by simp

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:40):

I want to reiterate the suggestion to separate the definition and the theorem

view this post on Zulip Kevin Buzzard (Apr 18 2020 at 21:41):

Yeah, it was only Reid who suggested to do them both at once, and now he's gone

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:41):

this gives you a lot more freedom to inspect and case analyze the definition in the theorem, because the inductions aren't wrapped up into one

view this post on Zulip Nam (Apr 18 2020 at 21:42):

the downside is it doesn't give me any assurance about the inputs / outputs.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:42):

Of course it does

view this post on Zulip Nam (Apr 18 2020 at 21:42):

i'm used to "contract" kind of defensive programming

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:42):

It gives you the assurance by its definition

view this post on Zulip Nam (Apr 18 2020 at 21:43):

it doesn't. my users can feed it any list.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:43):

The key thing that separates programming in lean from other functional languages you may be used to is that all defs are transparent; you know exactly what they evaluate to even after you are done with the definition itself

view this post on Zulip Nam (Apr 18 2020 at 21:43):

(even though it is an internal function for insertion sort and users shouldn't see it)

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:43):

they can, and they will get what they get

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:44):

and there are equations telling them what they will get

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:44):

but the point that I want to make here is that even your "improved" function, saying that it returns a sorted list, isn't good enough because you will want to know more than that

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:45):

what good is an insertion sort function that always returns []? or [0]?

view this post on Zulip Nam (Apr 18 2020 at 21:45):

yes, that's a fair critique.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:45):

but in lean, you can also look at the definition later and see what it does, and prove more theorems about the definition

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:46):

and for this it is best if the definition is as simple and nondependent as possible

view this post on Zulip Nam (Apr 18 2020 at 21:47):

are you saying that "dependent types" should be used more in proving than, erm, for the lack of better words, coding?

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:48):

So you can write a function containing the "logical core" of insertion sort, with no sorted requirements, and then prove a theorem saying that this function produces sorted output from sorted input. You can also prove that it produces a permutation of x::xs (which you didn't put in the original definition), or even more precisely you can prove that there exist l1 l2 such that xs = l1 ++ l2 and the output is l1 ++ x :: l2

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:48):

That's right

view this post on Zulip Nam (Apr 18 2020 at 21:49):

i see. apparently i was hoping for something like https://en.wikipedia.org/wiki/Design_by_contract but at compile time.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:50):

Oh, I'm not done. Once you've done all that, it is now trivial to write insertion_sort : A -> {l : list A // sorted l} -> {l : list A // sorted l}

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:50):

and this will give you all the contracts you want

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:52):

But the core of the program involves assumptions only rarely. The main place you see assumptions showing up in the "coding" part is to avoid unreachable branches, for example in list.nth_le (l : list A) (n : nat) : n <= length l -> A

view this post on Zulip Nam (Apr 18 2020 at 21:52):

i see. is that the same list l in both output and input?

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:52):

no

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:52):

there are two separate binders

view this post on Zulip Nam (Apr 18 2020 at 21:53):

then it won't solve the argument you mentioned before, that the output isn't related to the input.

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:53):

you are right

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:54):

but you can also have an improved insertion sort contract like insertion_sort (x : A) (l : list A) : sorted l -> {l' : list A // sorted l' /\ x::l ~ l'}

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:54):

where now the postcondition is relating the output to the input

view this post on Zulip Nam (Apr 18 2020 at 21:55):

i see. i assume that this separation would be easier to prove (via composition etc.)

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:55):

and hint hint this kind of style can also be used for a direct induction proof

view this post on Zulip Nam (Apr 18 2020 at 21:56):

yeah, so i was going to ask, what if i strengthen the postcondition of ins_sort_insert...

view this post on Zulip Mario Carneiro (Apr 18 2020 at 21:57):

yes, there is a way to strengthen the postcondition such that you can prove the theorem. If you try proving the theorem as is you will eventually get stuck and the place where you get stuck will give you the hint for what to put in the postcondition

view this post on Zulip Nam (Apr 18 2020 at 21:59):

sounds good! thank you, folks. this practice has yielded much more insights than i hoped for.

view this post on Zulip Scott Morrison (Apr 18 2020 at 23:18):

Kevin Buzzard said:

category is for computer scientists only

I'd like to rename category to control, and category_theory to category. How would people feel about this? (Possibly some alternatives to control?) I could update the docs explaining the connection between the two.

view this post on Zulip Nam (Apr 18 2020 at 23:57):

what is control about? Z-transform? you know, there's control theory too ;)

view this post on Zulip Reid Barton (Apr 18 2020 at 23:58):

The root problem (so to speak) is that functor and all that stuff is not in any namespace.

view this post on Zulip Reid Barton (Apr 18 2020 at 23:59):

I was going to suggest moving it into category but we could also change the name.

view this post on Zulip Scott Morrison (Apr 19 2020 at 00:06):

If we commit to a name, I could move functor and friends in core into that namespace, and then make the rename in mathlib once that lands. (I guess in 3.10 or beyond!)

view this post on Zulip Reid Barton (Apr 19 2020 at 00:07):

I assume the name control comes from the Haskell library though I don't know specifically how that name was chosen

view this post on Zulip Scott Morrison (Apr 19 2020 at 00:08):

I just remember control being suggested as an alternative last time we talked about this.

view this post on Zulip Scott Morrison (Apr 19 2020 at 00:08):

I do sort of like the Haskell connotation: "you'll feel at home in this directory if you learnt category theory from Haskell".

view this post on Zulip Jasmin Blanchette (Apr 19 2020 at 08:05):

@Nam your star syntax is a bit off. Try (hab : star r a b) and similarly for star r b c. I don't know why Lean forces you to specify names here.

view this post on Zulip Kenny Lau (Apr 19 2020 at 08:52):

import tactic

inductive sorted : list  -> Prop
| nil {} : sorted []
| one {x : } : sorted [x]
| other {x y : } {tail : list } (h: x <= y) (hs : sorted (y :: tail)) : sorted (x :: y :: tail)

lemma sorted_tail_of_sorted {hd tl} (HL : sorted (hd::tl)) : sorted tl :=
by { cases HL, constructor, assumption }

def insertion_sort_core :   list   list 
| x []       := [x]
| x (hd::tl) := if x  hd then x::hd::tl else hd :: (insertion_sort_core x tl)

theorem insertion_sort_aux {n L} (HL : sorted L) : sorted (insertion_sort_core n L) :=
begin
  induction L with x tl ih, { exact sorted.one },
  unfold insertion_sort_core, split_ifs with hx, { exact sorted.other hx HL },
  specialize ih (sorted_tail_of_sorted HL),
  cases tl with y tl, { exact sorted.other (le_of_not_le hx) sorted.one },
  unfold insertion_sort_core at ih ,
  split_ifs at ih  with hy,
  { exact sorted.other (le_of_not_le hx) ih },
  { cases HL, exact sorted.other x  y ih }
end

def insertion_core (n : ) (L : list ) (HL : sorted L) : { L' : list  // sorted L' } :=
insertion_sort_core n L, insertion_sort_aux HL

view this post on Zulip Kenny Lau (Apr 19 2020 at 08:52):

@Nam separate definition from theorems

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 08:54):

Ok so it was ten lines not five

view this post on Zulip Kenny Lau (Apr 19 2020 at 08:54):

maybe I should include more assertions

view this post on Zulip Mario Carneiro (Apr 19 2020 at 09:03):

I think you can skip sorted_tail_of_sorted if you cases HL instead of cases tl in insertion_sort_aux

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:07):

import tactic

inductive sorted : list  -> Prop
| nil {} : sorted []
| one {x : } : sorted [x]
| other {x y : } {tail : list } (h: x <= y) (hs : sorted (y :: tail)) : sorted (x :: y :: tail)

def insertion_sort_core :   list   list 
| x []       := [x]
| x (hd::tl) := if x  hd then x::hd::tl else hd :: (insertion_sort_core x tl)

theorem insertion_sort_aux {n L} (HL : sorted L) : sorted (insertion_sort_core n L) :=
begin
  induction L with x tl ih, { exact sorted.one },
  unfold insertion_sort_core, split_ifs with hx, { exact sorted.other hx HL },
  cases HL with _ _ y tl hxy htl, { exact sorted.other (le_of_not_le hx) sorted.one },
  unfold insertion_sort_core at ih , split_ifs at ih  with hy,
  { exact sorted.other (le_of_not_le hx) (ih htl) },
  { exact sorted.other hxy (ih htl) }
end

def insertion_core (n : ) (L : list ) (HL : sorted L) : { L' : list  // sorted L' } :=
insertion_sort_core n L, insertion_sort_aux HL

view this post on Zulip Mario Carneiro (Apr 19 2020 at 09:13):

did you want to call the final function insertion_sort instead of insertion_core?

view this post on Zulip Mario Carneiro (Apr 19 2020 at 09:14):

also we would normally call the theorem insertion_sort_core_sorted

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:16):

yeah I meant insertion_sort

view this post on Zulip Luca Seemungal (Apr 19 2020 at 09:44):

how do i use a stronger induction principle that usual? so i want something like
property holds for 0 and 1, and if property holds for n and n+1, then property holds for n+2

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:45):

Deleted

view this post on Zulip Mario Carneiro (Apr 19 2020 at 09:45):

You can often get the equation compiler to prove these for you

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:45):

(typo fixed)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:46):

Luca I have a good exercise for you

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:46):

Why not formalise the statement of the theorem you want?

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:46):

consider the property "n <= 2"

view this post on Zulip Luca Seemungal (Apr 19 2020 at 09:47):

ok i'll try that

view this post on Zulip Luca Seemungal (Apr 19 2020 at 09:47):

also whats an equation compiler, how do I use it

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:48):

Ie theorem luca_induction which takes P: nat -> Prop and the assumptions that P 0 and P 1 and the inductive hyp and the conclusion is for all n, P n

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:48):

Forget about the equation compiler for now

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:48):

That only works in toy examples

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:48):

You can't do it in the middle of a tactic proof

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:48):

That's the CS approach

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:48):

Kevin Buzzard said:

You can't do it in the middle of a tactic proof

factor it out

view this post on Zulip Mario Carneiro (Apr 19 2020 at 09:49):

you can use the equation compiler to prove luca_induction though

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:49):

Forget about the equation compiler

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:49):

It's a great trick once you know what you're doing

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:49):

Let's start by formalising the statement

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:49):

what will you do in the middle of a tactic proof

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:49):

And then let's formalise the proof

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:50):

And then let's use the equation compiler after

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:51):

The equation compiler is term mode trickery. There is a more basic principle at stake here which can be entirely dealt with in tactic mode

view this post on Zulip Luca Seemungal (Apr 19 2020 at 09:54):

ok

p is our predicate on the naturals, and we're supposing that p holds for some n₀ and n₀+1, and we're also supposing that if p holds for some n and n+1 then it holds for n+2. From that we want to prove that p holds for any n

theorem luca_induction (p :   Prop) (n₀ : ) (n : ) (h₀ : p n₀)
    (h₁ : p (n₀+1)) (H : p n  p (n+1)  p (n+2)) :
p n := sorry

view this post on Zulip Luca Seemungal (Apr 19 2020 at 09:55):

i'll have a stab at proving it now

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:56):

consider p n = (n <= 2), n0 = 0, n = 37

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:56):

You have to get the statement right first

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:56):

This is a really good exercise

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 09:56):

It's all about getting the quantifiers in the right order

view this post on Zulip Luca Seemungal (Apr 19 2020 at 09:57):

ah right yes

theorem luca_induction (p :   Prop) (n₀ : ) (n₁ : ) (n : ) (h₀ : p n₀)
    (h₁ : p (n₀+1)) (H : p n  p (n+1)  p (n+2)) : (hn : n  n₀)  p n := sorry

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:58):

theorem bad_induction_1 :
  ¬  (p :   Prop) (n₀ : ) (n : ) (h₀ : p n₀) (h₁ : p (n₀+1)) (H : p n  p (n+1)  p (n+2)), p n :=
λ H, absurd (H (λ n, n  2) 0 37 dec_trivial dec_trivial dec_trivial) dec_trivial

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:59):

the new one doesn't even compile

view this post on Zulip Luca Seemungal (Apr 19 2020 at 09:59):

oh gosh yes

view this post on Zulip Kenny Lau (Apr 19 2020 at 09:59):

but still:

theorem bad_induction_2 :
  ¬  (p :   Prop) (n₀ : ) (n : ) (h₀ : p n₀) (h₁ : p (n₀+1)) (H : p n  p (n+1)  p (n+2)) (hn : n  n₀) , p n :=
λ H, absurd (H (λ n, n  2) 0 37) dec_trivial

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:00):

@Kevin Buzzard I discovered the golf by accident lol

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:00):

theorem luca_induction (p :   Prop) (n₀ : ) (n : ) (h₀ : p n₀)
    (h₁ : p (n₀+1)) (H : p n  p (n+1)  p (n+2)) (hn : n  n₀) : p n := sorry

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:00):

oh right

hmmm

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:00):

ill have another little think

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:03):

If you want a hint Luca you could try #check nat.induction_on or something, to see the statement of usual induction written as a function in Lean

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:03):

I'm not sure what the actual term is called, I'm not at a computer right now

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:04):

nat.rec_on

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:04):

For every attempt of yours which compiles there's a little game which is to either formally prove it or formally disprove it

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:05):

Kenny I don't want something which mentions Sort ideally

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:05):

Luca is an UG mathematician like you

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:05):

there's nothing that doesn't mention Sort

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:06):

Oh rotten luck

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:06):

Well we'll just have to remember that Prop is Sort 0

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:12):

Ah, I see where my mistake is!

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:12):

theorem luca_induction (p :   Prop) (n : ) (n₀ : ) (h₀ : p n₀  p (n₀+1))
    (H :  n : , p n  p (n+1)  p (n+2)) (hn : n  n₀) := sorry

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:12):

that should have fixed it

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:12):

except it doesn't compile again

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:12):

you're right, i ignored the red squiggly line

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:13):

theorem luca_induction (p :   Prop) (n : ) (n₀ : ) (h₀ : p n₀  p (n₀+1))
    (H :  n : , p n  p (n+1)  p (n+2)) (hn : n  n₀) : p n := sorry

this one doesn't have any red squiggly lines, sorry about that

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:14):

that looks correct

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:15):

@Kevin Buzzard what's the next step

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:16):

i guess i'll start proving it, my first guess is to try

cases classical.em (n = n₀ ∨ n = n₀+1),

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:19):

maybe Kevin will tell you to write down the proof in maths first

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:21):

good point

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:29):

Sorry, was dealing with reality

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:29):

Now let's prove it in tactic mode by induction!

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:31):

The question now is precisely which statement we're going to prove by induction

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:32):

We need some other statement Q(n) such that Q(n_0) is true, and Q(m)->Q(m+1), and Q(m)->P(m)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:32):

We're doing two things at once. Can we start with n_0=0?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:33):

theorem luca_induction_aux (p :   Prop) (n : )  (h₀ : p 0  p 1)
    (H :  n : , p n  p (n+1)  p (n+2)) : p n :=
begin
  sorry
end

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:33):

I reckon that level is solvable

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:33):

ok, i'll give it a go

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:34):

but when Lean defines nat you get the two constructors zero and succ, and just the one eliminator, which is proof by normal induction

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:34):

So you need to find Q which is provable by normal induction and which implies P

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:35):

Q(m) = P(m-1) and P(m)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:35):

Subtraction is always bad

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:35):

this is nat

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:35):

You won't be able to prove m-1+1=m because it's not true

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:35):

right ok I see

i might have also got my Qs and Ps mixed up

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:38):

yes ok i think i've got it

Q(m) = P(m) and P(m+1)

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:39):

Q(0) = P(0) and P(1) which are both true so Q(0) is true

if Q(m) is true, then P(m) and P(m+1) are true, but then we also have that P(m+2) is true, so we have that Q(m+1) is true

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:40):

Right

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:41):

So the first line of your proof is have Q : forall n, P n and P n+1,

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:41):

And then { } because we're starting a new goal

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:42):

And in the bracket intro m, induction m with d hd

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:42):

And we're on the way

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:42):

cool! thanks for this!

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:49):

are there any style issues with this code?

theorem luca_induction (p :   Prop) (n : ) (h : p 0  p 1)
    (H :  n : , p n  p (n+1)  p (n+2)) : p n :=
begin
    have q : forall n, p (n)  p (n+1),
    {
        intro m,
        induction m with m hm,
        { simp, exact h, },
        {
            have h2 :=  H m hm.left hm.right,
            exact and.intro hm.right h2,
        }
    },
    induction n with n hn,
    { exact h.left, },
    { exact (q n).right, }
end

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:51):

Do you need induction at the end?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:51):

I mean can't you just prove p n from q n?

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:52):

no, youre right, i dont. I just need exact (q n).left

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:52):

You committed a cardinal sin in your base case, you used a non terminal simp

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:52):

theorem luca_induction (p :   Prop) (n : ) (h : p 0  p 1)
  (H :  n : , p n  p (n+1)  p (n+2)) : p n :=
begin
  suffices q : p n  p (n+1),
  { exact q.left },
  induction n with n ih,
  { exact h },
  { exact ih.right, H n ih.left ih.right }
end

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:52):

Kenny is sin free

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:53):

He's also written the proof backwards

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:53):

He deduced p from q first

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:53):

yes, i don't need that simp either

I just kind of assumed i needed to simp 0+1 to 1 or whatever

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:53):

You know 0+1=1 is true by definition?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:54):

Try removing the simp completely

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:54):

what is a non terminal simp? I assume it's a simp that doesn't terminate, but how do you tell (without going into the halting problem) beforehand

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:54):

terminal = final = at the end

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:54):

if it didn't terminate your proof wouldn't have compiled

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:54):

ohhh right

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:54):

You should never use simp to make a goal simpler

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:55):

You should only use it to kill a goal completely

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:55):

What happens if you remove the simp?

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:55):

ah ok

everything works without the simp

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:56):

at this point we're getting into:

  1. definitional equality
  2. mechanism of simp

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:56):

Kevin Buzzard said:

You know 0+1=1 is true by definition?

I see, so lean will just know because it'll unfold the definitions or something?

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:56):

I'm not sure if Luca is comfortable with discussing these two concepts

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:57):

haha probably not

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:57):

In the natural number game there is zero_add and add_zero

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:57):

"equality is just equality, right?"

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:57):

And one of them is true by definition

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:57):

Because x+0 is defined to be x

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:57):

But the other one is true because of a theorem

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:58):

ah yes i remember this now

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:58):

Which is proved by induction on x

view this post on Zulip Luca Seemungal (Apr 19 2020 at 10:58):

but once you've proved the theorem, surely it doesn't matter whether its true by definition or by theorem, it's just true?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:58):

So 0+1 is by definition 0+succ(0)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:58):

Which is by definition succ(0+0)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:59):

Which is by definition succ (0)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 10:59):

Which is by definition 1

view this post on Zulip Kenny Lau (Apr 19 2020 at 10:59):

0+1 → nat.add 0 1 → nat.add 0 (nat.succ 0) → nat.succ (nat.add 0 0) → nat.succ 0
1 → nat.succ 0

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:00):

The rw tactic really needs to see things being exactly equal, the same buttons on your keyboard equal, before it will work

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:00):

But the exact tactic will work up to definitional equality

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:00):

I can't get Lean to show me this (using set_option trace.type_context.is_def_eq_detail true) only tells me:

[type_context.is_def_eq_detail] [1]: p 0  p 1 =?= p 0  p (0 + 1)
[type_context.is_def_eq_detail] [2]: p 0 =?= p 0
[type_context.is_def_eq_detail] [3]: 0 =?= 0
[type_context.is_def_eq_detail] [2]: p 1 =?= p (0 + 1)
[type_context.is_def_eq_detail] [3]: 1 =?= 0 + 1
[type_context.is_def_eq_detail] process_assignment ?m_1 := h
[type_context.is_def_eq_detail] [1]: p 0  p (0 + 1) =?= p 0  p 1
[type_context.is_def_eq_detail] [2]: p 0 =?= p 0
[type_context.is_def_eq_detail] [3]: 0 =?= 0
[type_context.is_def_eq_detail] [2]: p (0 + 1) =?= p 1
[type_context.is_def_eq_detail] [3]: 0 + 1 =?= 1
[type_context.is_def_eq_detail] assign: ?m_1 := h

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:00):

Ok lemme get to a computer

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:01):

Kevin Buzzard said:

The rw tactic really needs to see things being exactly equal, the same buttons on your keyboard equal, before it will work

this is a rule with 37 exceptions

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:02):

Ok so now let's use luca_induction_aux

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:02):

@Luca Seemungal anyway this is how simp works: we have a database of "simp lemmas" (i.e. theorems we have tagged with @[simp]), and then simp tries to simplify the goal using each of them, until it reaches true

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:02):

ah I see

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:02):

so the reason you shouldn't use non-terminal simp is because you can't predict the outcome of simp

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:03):

because anyone can add simp lemmas

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:03):

then your proof might not compile, because the rest of the proof after simp relied on the exact form of the goal after using simp

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:04):

def fib :   
| 0 := 0
| 1 := 1
| (n+2) := fib (n+1) + fib(n)

lemma fib_zero : fib 0 = 0 := rfl

lemma fib_one : fib 1 = 1 := rfl

lemma fib_ss (n : ) : fib(n+2)=fib(n+1)+fib(n) := rfl

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:04):

but I've always been advocating not to use simp at all, because it's an expensive tactic

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:04):

i.e. it's slow

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:04):

theorem fib_nonneg :  n : , 0  fib(n) :=
begin
  sorry
end

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:05):

There's a theorem which you can't prove by usual induction.

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:05):

If you try proving it by induction, then the inductive case is Fn0    Fn+10F_n\geq0\implies F_{n+1}\geq0

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:05):

and you can't prove it because maybe Fn1<0F_{n-1}<0. You know in your heart that this is not going to be the case in practice, but induction is brutal and won't let you cheat like that

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:07):

But we can prove it with luca_induction

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:07):

right yes, I see. The fibonacci numbers was something I had in mind when doing this double induction thing

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:08):

So we start the proof of fib_nonneg with intro n

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:08):

and then we want to apply luca_induction somehow, but we need to give it some inputs

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:09):

Well, we could give it p, but given that we know that p n is supposed to be 0 <= fib(n) Lean will be able to work out p

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:09):

ah thats quite cool

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:09):

but we will have to tell it that we're doing induction on n rather than some other random integer variable like n^2

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:09):

so I'm hoping apply luca_induction _ n will work for the next line

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:10):

and it does :-)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:10):

import tactic -- always handy

theorem luca_induction (p :   Prop) (n : ) (h : p 0  p 1)
    (H :  n : , p n  p (n+1)  p (n+2)) : p n :=
begin
    have q : forall n, p (n)  p (n+1),
    {
        intro m,
        induction m with m hm,
        { exact h, },
        {
            have h2 :=  H m hm.left hm.right,
            exact and.intro hm.right h2,
        }
    },
    induction n with n hn,
    { exact h.left, },
    { exact (q n).right, }
end

def fib :   
| 0 := 0
| 1 := 1
| (n+2) := fib (n+1) + fib(n)

lemma fib_zero : fib 0 = 0 := rfl

lemma fib_one : fib 1 = 1 := rfl

lemma fib_ss (n : ) : fib(n+2)=fib(n+1)+fib(n) := rfl

theorem fib_nonneg :  n : , 0  fib(n) :=
begin
  intro n,
  apply luca_induction _ n,
  { sorry},
  { sorry}
end

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:10):

don't you have to tell lean about fib_zero and fib_one?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:10):

Note new line 1

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:11):

obviously you don't i guess it figures it out

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:11):

yeah ok I see

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:11):

When we apply your induction theorem, a bunch of new goals appear!

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:11):

the correct tactic is induction n using luca_induction,

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:12):

Your way might be the "correct" way but look at the mess it causes

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:12):

case h
 (λ (n : ), 0  fib n) 0  (λ (n : ), 0  fib n) 1

case H
n_n : ,
n_a : 0  fib n_n,
n_a_1 : 0  fib (n_n + 1)
 0  fib (n_n + 2)

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:12):

do I always have to put the underscore before any variable that I specify myself?

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:12):

what's the rules regarding these underscores?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:12):

My way:

2 goals
n : 
 0  fib 0  0  fib 1

n : 
  (n : ), 0  fib n  0  fib (n + 1)  0  fib (n + 2)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:13):

underscore just means "I don't want to tell you this right now"

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:13):

"either work it out for yourself or leave it to me as a new goal"

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:13):

ah ok

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:13):

theorem fib_nonneg :  n : , 0  fib(n) :=
begin
  intro n,
  apply luca_induction _ n _ _,
end

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:13):

@Mario Carneiro why does induction _ using _ create un-beta-reduced goals?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:14):

"I don't want to tell you p, and I don't want to tell you the proof of p0 and p1, and I don't want to tell you the proof of the inductive step"

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:14):

refine is better than apply if you want to specify all the underscores anyway

view this post on Zulip Patrick Massot (Apr 19 2020 at 11:14):

This is a secret code. induction ... using ... is a coded way to tell Lean you want to suffer.

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:15):

and Lean replies "well, for this apply tactic to work at all, I'd better make sure that p n equals 0 <= fib(n), so I can figure out that p must be "forall n, 0 <= fib(n)", but I can't figure out the proofs of the base case and the inductive step so I'll just leave them to you as new goals"

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:15):

p is "fun n, 0 < fib n"

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:16):

apply is a clever tactic, when we apply luca_induction _ n it says "hey wait a minute, luca_induction is a function with four inputs, I'll just add in two underscores"

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:17):

refine luca_induction _ n _ _ also works, but refine luca_induction _ n doesn't, because refine is more fussy, it wants the exact number of holes

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:18):

i see

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:18):

So now can you finish the proof?

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:18):

so when would one use refine instead of apply

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:18):

when you run into the apply bug :-)

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:18):

when you're me

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:18):

yes I can

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:19):

cheers!!

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:19):

hahahaah, I'll keep an eye out

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:19):

So this is a general principle. If you want a fancier induction, you can typically make it yourself.

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:19):

Shing and I made a new induction principle for multivariable polynomials just a couple of weeks ago

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:20):

we wanted to prove something about partial differentiation on multivariable polynomials and we couldn't find the principle we wanted so we just proved a new one like this

view this post on Zulip Mario Carneiro (Apr 19 2020 at 11:20):

I never use induction using

view this post on Zulip Mario Carneiro (Apr 19 2020 at 11:20):

refine does more or less the same thing

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:21):

then what's the point of induction using

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:21):

I mean, induction doesn't give you un-beta-reduced goals

view this post on Zulip Mario Carneiro (Apr 19 2020 at 11:21):

:shrug:

view this post on Zulip Patrick Massot (Apr 19 2020 at 11:21):

It's meant to try harder to elaborate

view this post on Zulip Mario Carneiro (Apr 19 2020 at 11:22):

Note that you have to mark your custom induction principle with @[elab_as_eliminator] for unification to work properly

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:22):

@Luca Seemungal for homework you can try and figure out how to start at n0n_0 :-)

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:22):

I tried that, it still don't beta reduce

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:23):

also it worked without that

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:23):

You might have to get your hands dirty with natural number subtraction though :-(

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:23):

breaking news: Mario doesn't understand Lean :P

view this post on Zulip Mario Carneiro (Apr 19 2020 at 11:23):

What did you try it on?

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:24):

theorem luca_induction {p :   Prop} (n : ) (h : p 0  p 1)
  (H :  n : , p n  p (n+1)  p (n+2)) : p n :=
begin
  suffices q : p n  p (n+1),
  { exact q.left },
  induction n with n ih,
  { exact h },
  { exact ih.right, H n ih.left ih.right }
end

def fib :   
| 0 := 0
| 1 := 1
| (n+2) := fib (n+1) + fib(n)

lemma fib_zero : fib 0 = 0 := rfl

lemma fib_one : fib 1 = 1 := rfl

lemma fib_ss (n : ) : fib(n+2)=fib(n+1)+fib(n) := rfl

theorem fib_nonneg :  n : , 0  fib(n) :=
λ n, luca_induction n _ _

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:24):

works perfectly

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:24):

PS @Luca Seemungal I defined Fibonacci numbers using the equation compiler. As you can see, to prove that this even is a valid definition there must be somewhere some form of your induction principle going on in the background.

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:24):

Kevin Buzzard said:

You might have to get your hands dirty with natural number subtraction though :-(

no you don't

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:25):

The equation compiler is those funny |s in definitions. It's a very cool little tool for playing around with basic stuff like this and the CS people are sometimes super-excited about how clever it can be, but because you can only use it in a definition rather than in the middle of things it's often a bit limited in mathematics.

view this post on Zulip Luca Seemungal (Apr 19 2020 at 11:27):

is this an "inductive type" that I've seen in TPIL

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:28):

an inductive type is what allows you to use the equation compiler

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:28):

Here's a proof of fib_nonneg which uses the equation compiler:

theorem fib_nonneg :  n : , 0  fib(n)
| 0 := by {rw fib_zero}
| 1 := by {rw fib_one, linarith}
| (n+2) := by {rw fib_ss, have hn := fib_nonneg n, have hn2 := fib_nonneg (n+1), linarith}

Yes, fib is an inductive type.

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:29):

Note that we do not need your inductive principle at all. It's somehow inbuilt into the equation compiler. As I say, it's cool but limited.

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:30):

fib is not an inductive type

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:30):

rotten luck

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:31):

I still don't understand the basics

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:31):

What I know is that you don't need to :-)

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:31):

It's a function so it's a pi type I guess

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:31):

nat is the inductive type

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:31):

so that's why I can use the equation compiler

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:32):

You can't prove that partial differentation is additive using the equation compiler because polynomials are not an inductive type. You have to make your own induction principles for them.

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:33):

I tried to make polynomials an inductive type very early on in my Lean experience

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:33):

it failed miserably

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:33):

You will have problems with uniqueness

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:34):

well you can require the first coefficient to not be zero

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:34):

Although you can make them a quotient of an inductive type and then use quotient.induction but then you can't use the equation compiler because you're in the middle of something.

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:35):

I see, you can define a polynomial to be either 0 or c*X^n+a polynomial with c non-zero

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:35):

It would be hell to work with though, making the basic interface would be a real pain

view this post on Zulip Kenny Lau (Apr 19 2020 at 11:35):

exactly

view this post on Zulip Reid Barton (Apr 19 2020 at 11:35):

In HoTT you would be able to use the equation compiler for a quotient.

view this post on Zulip Mario Carneiro (Apr 19 2020 at 11:35):

Kenny Lau said:

works perfectly

Or does it?

theorem fib_nonneg (h1 : 0  fib 0  0  fib 1) :  n : , 0  fib(n) :=
λ n, luca_induction n h1 _

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 11:36):

maximum class-instance resolution depth has been reached (the limit can be increased by setting option 'class.instance_max_depth') (the class-instance resolution trace can be visualized by setting option 'trace.class_instances')

view this post on Zulip Ashwin Iyengar (Apr 19 2020 at 15:43):

If I try

universe u

class discrete_valuation_ring (α : Type u) extends principal_ideal_domain α :=
(prime_ideal : ideal α)
(is_prime : prime_ideal.is_prime)
(unique_nonzero_prime_ideal :  P : ideal α, P.is_prime  P = 0  P = prime_ideal)

namespace discrete_valuation_ring

variable {α : Type u}
variables [discrete_valuation_ring α]

#check prime_ideal

lemma prime_ideal_is_maximal : prime_ideal.is_maximal :=
begin
sorry,
end

end discrete_valuation_ring

then I get

don't know how to synthesize placeholder
context:
 Type ?

I'm sure I'm misunderstanding something basic here. How can I write down the proposition which just states that in discrete_valuation_ring the ideal prime_ideal is maximal?

view this post on Zulip Kenny Lau (Apr 19 2020 at 15:46):

alpha cannot be inferred

view this post on Zulip Kenny Lau (Apr 19 2020 at 15:46):

how about (prime_ideal \a).is_maximal

view this post on Zulip Ashwin Iyengar (Apr 19 2020 at 15:48):

then I get

function expected at
  prime_ideal
term has type
  submodule ?m_1 ?m_1

and

invalid field notation, type is not of the form (C ...) where C is a constant
  
has type
  ?m_1

view this post on Zulip Ashwin Iyengar (Apr 19 2020 at 15:48):

the #check part actually works, it's the lemma where it fails

view this post on Zulip Kenny Lau (Apr 19 2020 at 15:55):

then (@prime_ideal \a).is_maximal

view this post on Zulip Ashwin Iyengar (Apr 19 2020 at 15:58):

hmm then i get

invalid field notation, type is not of the form (C ...) where C is a constant
  prime_ideal
has type
  Π [c : discrete_valuation_ring α], ideal α

view this post on Zulip Reid Barton (Apr 19 2020 at 15:59):

(prime_ideal : ideal \a).is_maximal?

view this post on Zulip Ashwin Iyengar (Apr 19 2020 at 16:02):

oh that works! do you know why? naively i would think that it shouldn't be necessary to specify that prime_ideal is an ideal in \alpha, but i must be misunderstanding something

view this post on Zulip Reid Barton (Apr 19 2020 at 16:10):

Well, it could be, like, \beta instead. Why not?

view this post on Zulip Reid Barton (Apr 19 2020 at 16:10):

I don't really know how to explain this.

view this post on Zulip Reid Barton (Apr 19 2020 at 16:13):

There's no reason for it to know you mean \alpha, so it doesn't know.

view this post on Zulip Ashwin Iyengar (Apr 19 2020 at 16:36):

I guess my confusion is that writing variable [discrete_valuation_ring \alpha] doesn't make lean automatically guess that prime_ideal should be an ideal in \alpha?

view this post on Zulip Reid Barton (Apr 19 2020 at 16:44):

No, instances don't work that way (this is a common confusion). It just means that Lean can use the fact that \alpha is a DVR if it needs it.
Imagine you had a second

variable {beta : Type u}
variables [discrete_valuation_ring beta]

and this should probably be clearer.

view this post on Zulip Ashwin Iyengar (Apr 19 2020 at 16:53):

ohh ok that makes more sense. thanks

view this post on Zulip Nam (Apr 19 2020 at 17:07):

Jasmin Blanchette said:

Nam your star syntax is a bit off. Try (hab : star r a b) and similarly for star r b c. I don't know why Lean forces you to specify names here.

Yes. I tried to formulate it again after reading your doc. I think I have a shorter and more syntactically consistent. I was going to send your a PR then I found out that you have not published the text yet (only PDF is availabe).

view this post on Zulip Nam (Apr 19 2020 at 17:09):

Kenny Lau said:

Nam separate definition from theorems

Thanks!

view this post on Zulip Aniruddh Agarwal (Apr 19 2020 at 17:20):

I'm trying to use the use tactic from the "natural numbers game", but it appears this tactic is not available in lean by default. What do I need to import to make it available?

view this post on Zulip Reid Barton (Apr 19 2020 at 17:31):

import tactic should do it

view this post on Zulip Reid Barton (Apr 19 2020 at 17:31):

It's part of mathlib

view this post on Zulip Jannis Limperg (Apr 19 2020 at 17:54):

@Aniruddh Agarwal To see all the mathlib tactics and which import incantation you need, check the index.

view this post on Zulip Aniruddh Agarwal (Apr 19 2020 at 21:46):

This really is a noob question, but how do I close a proof if my goal is "true"?

view this post on Zulip Jason KY. (Apr 19 2020 at 21:47):

trivial

view this post on Zulip Bryan Gin-ge Chen (Apr 19 2020 at 21:47):

example : true := trivial

view this post on Zulip Aniruddh Agarwal (Apr 19 2020 at 21:48):

Is it possible to just use these tactics to close true:

intro
apply (or, better, refine)
left, right, cases, split
assumption (or, better, exact)
have,
simp
contradiction (or, better, false.elim)

view this post on Zulip Bryan Gin-ge Chen (Apr 19 2020 at 21:48):

You can use exact trivial then.

view this post on Zulip Aniruddh Agarwal (Apr 19 2020 at 21:49):

Ah, is trivial both a tactic and a "term"?

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 21:50):

Does simp not do it??

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 21:50):

That looks like a fine list of tactics, by the way.

view this post on Zulip Aniruddh Agarwal (Apr 19 2020 at 21:50):

Nope, simp doesn't do it unfortunately

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:00):

rofl

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:00):

tauto! will presumably do it

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:00):

It does all logic proofs

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:00):

and finish will presumably do it too

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:00):

and maybe cc

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:01):

and it's always worth trying norm_num even though it wasn't designed to do it

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:01):

because it does random things it wasn't designed to do

view this post on Zulip Reid Barton (Apr 19 2020 at 22:02):

I've had simp reduce my goal to true before, it's a bit puzzling that it can't finish the job from there

view this post on Zulip Kevin Buzzard (Apr 19 2020 at 22:13):

Maybe we should add true \iff (true \iff true) as a simp lemma :-)

view this post on Zulip Brandon B (Apr 20 2020 at 07:25):

I don't understand this example in TPIL

example :  x : , x > 0 :=
        have h : 1 > 0, from nat.zero_lt_succ 0,
        exists.intro 1 h

It's as if the proposition 1 > 0 is being applied to the argument 1 but this proposition doesn't have any variables

view this post on Zulip Patrick Stevens (Apr 20 2020 at 07:32):

Brandon B said:

I don't understand this example in TPIL

example :  x : , x > 0 :=
        have h : 1 > 0, from nat.zero_lt_succ 0,
        exists.intro 1 h

It's as if the proposition 1 > 0 is being applied to the argument 1 but this proposition doesn't have any variables

Which part has you applying 1 > 0 to the argument 1? Line 1 is a type signature of the example; line 2 is the manifestation of a term of type 1 > 0; line 3 is the construction of an object of type ∃ x : ℕ, x > 0 from the two pieces of data 1 and h that comprise an existential statement.

view this post on Zulip Brandon B (Apr 20 2020 at 07:33):

I guess i dont understand line 3. Why would it need both 1 and 1 > 0. Shouldn't 1 > 0 suffice?

view this post on Zulip Brandon B (Apr 20 2020 at 07:36):

Nevermind - reading on I think I get it now

view this post on Zulip Luca Seemungal (Apr 20 2020 at 08:40):

what tactic do I use to solve the following example? norm_num doesn't do it, and i've no idea what else to use and I don't feel like expanding the brackets etc. Do I have to expand the brackets etc?

example : (1 + real.sqrt 2) ^ 2 / 3 = (2*real.sqrt 2) / 3 + 1 :=
begin
    norm_num, -- norm_num failed to simplify
    sorry,
end

view this post on Zulip Shing Tak Lam (Apr 20 2020 at 08:42):

try ring? Then norm_num?

view this post on Zulip Luca Seemungal (Apr 20 2020 at 08:44):

hmmm
lean is taking a long time to check that; it hasn't finished after half a minute

view this post on Zulip Shing Tak Lam (Apr 20 2020 at 08:45):

Yeah, that doesn't seem to work. ring did expand the brackets though.

view this post on Zulip Luca Seemungal (Apr 20 2020 at 08:45):

yes it did

view this post on Zulip Mario Carneiro (Apr 20 2020 at 08:50):

norm_num doesn't know about real.sqrt. If you view it as an atom x, then you will have to give it a hint that x^2 = 2 (as well as the hint of how to use that to finish the proof)

view this post on Zulip Johan Commelin (Apr 20 2020 at 08:52):

But simp does know about real.sqrt. Does that help?

view this post on Zulip Mario Carneiro (Apr 20 2020 at 08:57):

example : (1 + real.sqrt 2) ^ 2 / 3 = (2*real.sqrt 2) / 3 + 1 :=
calc  (1 + real.sqrt 2) ^ 2 / 3
    = (1 + 2 * real.sqrt 2 + real.sqrt 2 ^ 2) / 3 : by ring
... = (2*real.sqrt 2) / 3 + 1 : by rw real.sqr_sqrt; [ring, norm_num]

view this post on Zulip Luca Seemungal (Apr 20 2020 at 08:57):

example : (1 + real.sqrt 2) ^ 2 / 3 = (2*real.sqrt 2) / 3 + 1 :=
begin
    ring, -- ⊢ (1 / 3 * real.sqrt 2 + 2 / 3) * real.sqrt 2 + 1 / 3 = 2 / 3 * real.sqrt 2 + 1
    simp, -- ⊢ (3⁻¹ * real.sqrt 2 + 2 / 3) * real.sqrt 2 + 3⁻¹ = 2 / 3 * real.sqrt 2 + 1
    sorry
end

view this post on Zulip Luca Seemungal (Apr 20 2020 at 08:58):

simp doesn't solve the goal, and I've been told not to use a non terminal simp

view this post on Zulip Mario Carneiro (Apr 20 2020 at 08:58):

actually simp doesn't really do much of anything on that goal

view this post on Zulip Luca Seemungal (Apr 20 2020 at 08:58):

oh, cool

cheers!

view this post on Zulip Mario Carneiro (Apr 20 2020 at 08:59):

the antidote to non-terminal simp is saying what you want your intermediate goal to look like

view this post on Zulip Shing Tak Lam (Apr 20 2020 at 09:00):

Johan Commelin said:

But simp does know about real.sqrt. Does that help?

There are a few simp lemmas, but this doesn't work...

example : sqrt 2 * sqrt 2 = 2 :=
begin
  simp, -- fails
end

view this post on Zulip Marc Huisinga (Apr 20 2020 at 09:00):

you can also use simp only, but i think stating the intermediate goal is much nicer

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:00):

there is a side condition, isn't there? There was in the theorem I used

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:01):

example : real.sqrt 2 * real.sqrt 2 = 2 :=
by simp [show (0:)  2, by norm_num]

view this post on Zulip Shing Tak Lam (Apr 20 2020 at 09:02):

Ah. So that's how you provide that condition.

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:02):

you could also have it as a hypothesis

view this post on Zulip Luca Seemungal (Apr 20 2020 at 09:03):

i managed to solve it this way:

example : (1 + real.sqrt 2) ^ 2 / 3 = (2*real.sqrt 2) / 3 + 1 :=
begin
    ring,
    rw add_mul,
    have h2 := @real.sqrt_mul' 2 2 (by norm_num),
    rw mul_assoc,
    rw h2,
    have h3 := @real.sqrt_mul_self 2 (by norm_num),
    rw h3,
    ring,
end

but presumably Mario's way is better

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:04):

It's hard to say which approach I would use when golfing. Writing the type is often more verbose than tactic based proofs

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:05):

I don't usually use non-terminal ring either, although it does leave the goal in a fairly clean state

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:05):

In this case ring SOP puts you in a much better state

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:06):

example : (1 + real.sqrt 2) ^ 2 / 3 = (2*real.sqrt 2) / 3 + 1 :=
by ring SOP; rw real.sqr_sqrt; [ring, norm_num]

view this post on Zulip Johan Commelin (Apr 20 2020 at 09:13):

Hmmm... I think there is room for a little hammer here

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:13):

ring_with_sqrt?

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:14):

I mean it all fits into the Grobner basis tactic of the future, but I'm in no hurry to write it

view this post on Zulip Johan Commelin (Apr 20 2020 at 09:14):

https://en.wikipedia.org/wiki/Uchide_no_kozuchi

view this post on Zulip Mario Carneiro (Apr 20 2020 at 09:16):

Notice that this is a proof in rings modulo equalities, that is, x^2 = 2 -> (1 + x) ^ 2 / 3 = (2*x) / 3 + 1

view this post on Zulip Brandon B (Apr 20 2020 at 11:34):

This is really embarrassing but how do I prove some even number is even?

def is_even (a : ) :=  b, a = 2 * b
example : is_even 6 := _

view this post on Zulip Mario Carneiro (Apr 20 2020 at 11:35):

\<3, rfl\> should work

view this post on Zulip Brandon B (Apr 20 2020 at 11:35):

Indeed it does., thanks!

view this post on Zulip AMM (Apr 20 2020 at 12:52):

Hey! sorry, I was just trying what I thought was going to be a trivial example and I can't seem to make lean like my answer:

def axiom_5: ( x : α , (B x  C x))  (B y  ( y, C y)) :=
begin
intros h1 h2 y,
apply h1 y,
/- Tactic State
1 goal
α : Type,
B C : α → Prop,
y : α,
h1 : ∀ (x : α), B x → C x,
h2 : B y,
y : α
⊢ B y-/
assumption,
/- getting error:
assumption tactic failed
state:
α : Type,
B C : α → Prop,
y : α,
h1 : ∀ (x : α), B x → C x,
h2 : B y,
y : α
⊢ B y

If I do 'exact h2' I get:
invalid type ascription, term has type
  B y
but is expected to have type
  B y
types contain aliased name(s): y
remark: the tactic `dedup` can be used to rename aliases
state:
α : Type,
B C : α → Prop,
y : α,
h1 : ∀ (x : α), B x → C x,
h2 : B y,
y : α
⊢ B y
but then dedup doesn't seem to help progressing the proof very much
-/
end

view this post on Zulip Mario Carneiro (Apr 20 2020 at 12:53):

the theorem is false

view this post on Zulip Mario Carneiro (Apr 20 2020 at 12:54):

you have two variables named y (you can see them in your context) and this is getting you confused

view this post on Zulip Mario Carneiro (Apr 20 2020 at 12:55):

To make it clearer, your theorem is the same as

def axiom_5: ( x : α , (B x  C x))  (B y  ( z, C z)) := sorry

which should be more obviously false

view this post on Zulip AMM (Apr 20 2020 at 12:56):

I see my bad, that makes sense actually, I need B to not have free occurrences of the variable

view this post on Zulip Mario Carneiro (Apr 20 2020 at 12:56):

In which case you can write B instead of B y

view this post on Zulip AMM (Apr 20 2020 at 12:57):

right, but then " type expected at
B
term has type
α → Prop"
and it's used with B x before

view this post on Zulip Mario Carneiro (Apr 20 2020 at 12:59):

make it B there too and change the type of B to Prop

view this post on Zulip AMM (Apr 20 2020 at 12:59):

I think actually what I want is $(∀ x_i)(B → C) → (B → (∀ x_i)C)$ if $B$ has no free occurrences of $x_i$, so not what I wrote probably

view this post on Zulip AMM (Apr 20 2020 at 12:59):

that makes sense

view this post on Zulip Mario Carneiro (Apr 20 2020 at 13:00):

this amounts to exactly your not free condition since you can substitute any expression for B but it can't mention x because it is out of scope

view this post on Zulip AMM (Apr 20 2020 at 13:01):

I'd just used (∀ x_i)B(x_i) so forgot to get rid of variables and make a new section for this one

view this post on Zulip Mario Carneiro (Apr 20 2020 at 13:01):

you could also use a different letter if you don't want to change your variables

view this post on Zulip AMM (Apr 20 2020 at 13:03):

ofc, that would be good too
all good with

def axiom_5: ( x : α , B  C )  (B  ( x : α , C)) :=

view this post on Zulip AMM (Apr 20 2020 at 13:03):

stuff works as expected, thank you mario

view this post on Zulip Mario Carneiro (Apr 20 2020 at 13:52):

@AMM Actually, that's gone too far the other way, now. Because C doesn't depend on x, the binder over x is vacuous; that is, C is also being constrained to not mention x just as B is. As a result, this theorem is true but less applicable than it should be. You want (∀ x : α , B → C x) → (B → (∀ x : α , C x)) here

view this post on Zulip AMM (Apr 20 2020 at 13:58):

right ofc, i have fixed that now

def axiom_5: ( x : α , B  C x)  (B  ( x : α , C x)) :=
begin
intros h1 h2 y,
apply h1 y,
assumption,
end

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 15:27):

import tactic

variables (α : Type) (B : Prop) (C : α  Prop)

def axiom_5: ( x : α , B  C x)  (B  ( x : α , C x)) :=
begin
  finish,
end

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 15:28):

@Brandon B

import tactic

def is_even (a : ) :=  b, a = 2 * b
example : is_even 6 :=
begin
  unfold is_even,
  -- ⊢ ∃ (b : ℕ), 6 = 2 * b
  use 3,
  -- ⊢ 6 = 2 * 3
  norm_num
end

view this post on Zulip Ashwin Iyengar (Apr 20 2020 at 15:48):

Hi, can someone please let me know what I'm doing wrong here? I just want to say that an element of a ring is contained in the ideal generated by it

import ring_theory.ideals

universe u

variables {R : Type u} [nonzero_comm_ring R]

example (π : R) : Prop :=
begin
  have h : {π}  ideal.span {π} := ideal.subset_span {π},
end

view this post on Zulip Johan Commelin (Apr 20 2020 at 15:52):

have h : \pi \in ideal.span {\pi}, should also work...

view this post on Zulip Johan Commelin (Apr 20 2020 at 15:52):

@Ashwin Iyengar could you be more explicit about what you want to see? Do you not like the statement, or is there something else?

view this post on Zulip Kenny Lau (Apr 20 2020 at 15:55):

import ring_theory.ideals

universe u

variables {R : Type u} [nonzero_comm_ring R]

example (π : R) : true :=
begin
  have h : ({π} : set R)  (ideal.span {π}) := ideal.subset_span,
end
  1. the argument to ideal.subset_span is implicit, so it should not be supplied
  2. always specify that {π} is a set
  3. ideal.span {π} is an ideal, so you need to coerce it to a set

view this post on Zulip Ashwin Iyengar (Apr 20 2020 at 16:01):

ahh ok great thanks.

view this post on Zulip orlando (Apr 20 2020 at 16:43):

@Kevin Buzzard shorter :
def axiom_5: (∀ x : α , B → C x) → (B → (∀ x : α , C x)) := λ φ η , λ ζ , φ ζ η

view this post on Zulip Sebastien Gouezel (Apr 20 2020 at 17:26):

Kevin could have written

def axiom_5: ( x : α , B  C x)  (B  ( x : α , C x)) := by finish

or even

def axiom_5: ( x : α , B  C x)  (B  ( x : α , C x)) := by tauto

but he chose the longer form with begin ... end just for pedagogical reasons.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 17:29):

def axiom_5: (∀ x : α , B → C x) → (B → (∀ x : α , C x)) :=λφ η ζ,φ ζ η

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 17:30):

def axiom_5: (∀ x : α , B → C x) → (B → (∀ x : α , C x)) :=forall_swap.1

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 17:31):

variables (α: Type) (B : Prop) (C : α  Prop)

open function

def axiom_5: ( x : α , B  C x)  (B  ( x : α , C x)) := swap

view this post on Zulip Sebastien Gouezel (Apr 20 2020 at 17:32):

Hey, you opened function, this is cheating.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 17:33):

aah but I didn't import tactic

view this post on Zulip Sebastien Gouezel (Apr 20 2020 at 17:38):

Importing tactic is not cheating :)

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 18:03):

Indeed, it should be made mandatory!

view this post on Zulip Nam (Apr 20 2020 at 22:18):

what is this error induction tactic failed, recursor 'sorted.dcases_on' can only eliminate into Prop about?

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:18):

It probably means that you were in tactic mode, your goal was T with T : Type rather than P with P : Prop, and then you tried the cases tactic.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:19):

Maybe you were trying to get a : A from some statement of the form exists a : A (you weren't)

view this post on Zulip Nam (Apr 20 2020 at 22:19):

inductive sorted : list  -> Prop
| nil {} : sorted []
| one {x : } : sorted [x]
| other {x y : } {tail : list } (h: x <= y) (hs : sorted (y :: tail)) : sorted (x :: y :: tail)

lemma what_is_this {l} (h : sorted l) : Prop :=
begin
  cases h,
end

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:20):

Your goal is Prop and Prop : Type

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:20):

You can solve your goal with exact 2 + 2 = 37

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:21):

You probably want your goal to be P : Prop for some proposition P

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:21):

sorted.rec :
   {C : list   Prop},
    C list.nil 
    ( {x : }, C [x]) 
    ( {x y : } {tail : list }, x  y  sorted (y :: tail)  C (y :: tail)  C (x :: y :: tail)) 
     {a : list }, sorted a  C a

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:22):

That's the recursor which Lean has generated for sorted, and the motive C is a map list nat -> Prop so it will only work if your goal has type Prop. You have (probably unintentionally) made your goal equal to Prop, so in particular it has type Type

view this post on Zulip Nam (Apr 20 2020 at 22:24):

if i change the declaration of the lemma to lemma what_is_this {l} (h : sorted l) : sorted l :=, then i can cases h.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:24):

That's because now your goal is sorted l and sorted l : Prop

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:25):

cases will work if the type of your goal is Prop. If you are in tactic mode, the type of your goal should always be Prop.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:25):

Tactic mode is for proving theorems, and theorem statements are terms of type Prop.

view this post on Zulip Nam (Apr 20 2020 at 22:26):

what is the equivalence in a def?

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:26):

I don't understand the question.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:26):

Oh -- you mean the equivalent story?

view this post on Zulip Nam (Apr 20 2020 at 22:27):

i mean the equivalent "statement(?)"

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:27):

With a def, you are usually either making T with T : Type or t with t : T

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:27):

and you almost never do the entire thing in tactic mode

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:27):

Sometimes, making a definition involves doing some proofs along the way, and it's fine to go into tactic mode then

view this post on Zulip Nam (Apr 20 2020 at 22:28):

so how do you "cases" a hypothesis, or to extract the terms from that hypothesis?

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:28):

This question is too vague to admit an answer

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:29):

A lot will depend on the form of the recursor for the head term of the hypothesis

view this post on Zulip Nam (Apr 20 2020 at 22:29):

say, the signature def what_is_this {l} (h : sorted l) : N, how do i yield values depending on what form h is?

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:29):

If you are in tactic mode, then cases is almost always the right answer.

view this post on Zulip Nam (Apr 20 2020 at 22:29):

oh, i think "match ... with" is what i might be looking for. is it right?

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:30):

What is N? I think I am going to need a more precise question before I can help you.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:30):

h is a proof so it can't really help you with making a definition. It can only help you making other proofs.

view this post on Zulip Nam (Apr 20 2020 at 22:30):

i don't know how to type the math font for natural numbers

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:30):

Oh, just call them nat, that's their ASCII name

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:31):

How is the fact that you know a theorem about l going to help you define a natural number?

view this post on Zulip Nam (Apr 20 2020 at 22:31):

i was thinking of enums

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:31):

I don't know what they are.

view this post on Zulip Nam (Apr 20 2020 at 22:31):

converting sorted.nil / sorted.one / sorted.other into 0, 1 or 2

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:32):

But that can just be read off from the length of l

view this post on Zulip Nam (Apr 20 2020 at 22:32):

that's true.

view this post on Zulip Nam (Apr 20 2020 at 22:32):

but it won't be as natural

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:33):

Lean has a proof-irrelevant Prop. This means that h has no idea how it was proved.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:33):

I might be wrong about this, I don't know much about all this core logic stuff.

view this post on Zulip Nam (Apr 20 2020 at 22:34):

how does cases work though? it knows how h was constructed.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:34):

No it doesn't, it just splits into cases: "if h was constructed in this way, do this, if it was constucted in this other way, do that,..."

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:35):

and you can only do that whilst in the middle of another proof, because your recursor is only eliminating into Prop.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:35):

I have no idea whether you can make a recursor which eliminates into Type

view this post on Zulip Nam (Apr 20 2020 at 22:35):

that's exactly what i want. if h was constructed in this way, return 0, etc.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:35):

For all I know, this sort of functionality would make Lean inconsistent.

view this post on Zulip Reid Barton (Apr 20 2020 at 22:36):

Yes, it would

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:36):

It might be what you want, but it's a fact that Lean has a proof-irrelevant Prop.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:38):

In general this sort of thing could be quite problematic. For example if you had a proof h of A or B, and you wanted to define a function which was 1 if the thing you actually proved was A, and was 2 if the thing you actually proved was B, then imagine what happens if you have proofs of both?

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:39):

Any two proofs of A or B are equal by definition. Lean cannot tell or.inl hA and or.inr hB apart, they are both represented as a little tick by the statement A or B, representing the fact that it is proved.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:39):

And that's why or only eliminates to Prop.

view this post on Zulip Nam (Apr 20 2020 at 22:40):

i see. thanks for all the explanations!

view this post on Zulip Reid Barton (Apr 20 2020 at 22:40):

Since you are already thinking about programming: A Prop is not represented by any data at runtime. That's why you can't do case analysis on h : p if p is a Prop in order to construct data, because the data you would need to decide what to do does not exist. You can do case analysis on h to prove another Prop though, since that doesn't require constructing any data.

view this post on Zulip Reid Barton (Apr 20 2020 at 22:40):

And the reason that h is not represented by data is that any two proofs of a Prop are equal anyways, so there is no sense in it.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:41):

My understanding is that other proof systems do not have this spectacularly good idea inbuilt into them, because some people who do type theory are uncomfortable with this set-up.

view this post on Zulip Reid Barton (Apr 20 2020 at 22:41):

If you don't want this behavior, no problem: don't use Prop.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:41):

So then they have the joy of being able to worry about whether two proofs of something are equal, a concept which basically makes no sense to most mathematicians.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:44):

You could redefine sorted to be some kind of a data-carrying witness of the fact that your list is sorted. If your list is long then the data-carrying witness might be quite large.

view this post on Zulip Nam (Apr 20 2020 at 22:44):

got it.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:44):

Perhaps I should not say any more though because this really is at the edge of my understanding; I am not entirely clear on how this would work.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:46):

Oh it might be as easy as

inductive sorted : list  -> Type
| nil {} : sorted []
| one {x : } : sorted [x]
| other {x y : } {tail : list } (h: x <= y) (hs : sorted (y :: tail)) : sorted (x :: y :: tail)

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:47):

Now sorted l has type Type, the recursor (#check @sorted.rec) can be checked to have a motive C : Π (a : list ℕ), sorted a → Sort u_1 which is what you want, and the cases command will probably work.

view this post on Zulip Nam (Apr 20 2020 at 22:48):

it does seem to work.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:48):

But now later on if you have two terms a and b of type sorted l you will have to work to prove that they are equal.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:49):

You can recover your Prop-valued function by defining def is_sorted (l : list ℕ) := nonempty (sorted l)

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:51):

Because in your case the constructors work in disjoint cases (one only works when the list is empty, one only works when it has size 1 and the last one only works if the size is 2 or more) you should be able to prove subsingleton (sorted l), i.e. any two terms of type sorted l are equal.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:51):

(NB Sort 0 = Prop, Sort 1 = Type, Sort 2 = Type 1 etc)

view this post on Zulip Nam (Apr 20 2020 at 22:53):

these are pretty advanced tips ;). i think i get them, but not confident enough to explain them back to someone else. hah.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:53):

But this is a design decision which will come with consequences later; some of Lean's unification algorithms will not know that sorted l is a subsingleton and you might start getting weird errors. It also seems a bit strange to want to carry all this data around when you can instantly reconstruct it from the length of the list.

view this post on Zulip Nam (Apr 20 2020 at 22:54):

i don't have any specific need. i was just playing with the syntax to familiarize myself.

view this post on Zulip Nam (Apr 20 2020 at 22:54):

there are still so much to learn.

view this post on Zulip Kevin Buzzard (Apr 20 2020 at 22:55):

With the Type-valued sorted l all you have is another data structure, of the same size as l, which basically tells you nothing more than the fact that you checked a bunch of inequalities and they were all true, and it took time O(n) to do it, with n=length(l). With the Prop-valued sorted l you just have a tick in a box saying "I checked this, and it was fine". It costs you nothing extra and is free to carry around.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 21 2020 at 01:00):

ROCKY KAMEN-RUBIO said:

Bryan Gin-ge Chen said:

Oh, I see. Your file wasn't relying on mathlib at all before. So instead of just removing the inits from the imports, I would just delete the import data.nat.basic and import data.list.basic entirely.

If you do want to use stuff from mathlib, then you'll need to fix the path issue, and the best way to do that is to look at the install docs again, specifically the "project" doc if you've gotten leanproject working.

This seems to be what my problem was - must have built my current project workspace incorrectly. I follow the directions to make a new workspace and now import data.nat.basic doesn't error anymore. Thank you!

UPDATE: I suspect my issue was that I wasn't re-opening my entire workspace folder when I was opening new VSCode windows. This would explain why I had lost the mathlib dependency despite having installed mathlib when I created my workspace. Making a new workspace did this for me in my new VSCode window.

view this post on Zulip Nam (Apr 21 2020 at 04:36):

what is the syntax to return 2 lists, with some properties? e.g. def split (input : list nat) -> {(prefix suffix : list nat) // prefix ++ suffix = input} (this obviously doesn't work)

view this post on Zulip Mario Carneiro (Apr 21 2020 at 04:36):

You could return a pair, or you could use \Sigma prefix, {suffix // P prefix suffix}

view this post on Zulip Mario Carneiro (Apr 21 2020 at 04:38):

with a pair it would be something like {p : list nat \times list nat // p.1 ++ p.2 = input}

view this post on Zulip Nam (Apr 21 2020 at 04:38):

i also tried {(pre : list ℕ) × (suf : list ℕ) // pre++suf = input}

view this post on Zulip Nam (Apr 21 2020 at 04:38):

ahh, i see.

view this post on Zulip Nam (Apr 21 2020 at 04:38):

my understanding of pair is completely off.

view this post on Zulip Nam (Apr 21 2020 at 04:39):

thanks Mario

view this post on Zulip Mario Carneiro (Apr 21 2020 at 04:40):

If you don't like the asymmetry of the first version, you can also use \Sigma' which is a generalization of \Sigma and {x // p x}, as in \Sigma' prefix suffix, prefix ++ suffix = input

view this post on Zulip Kevin Buzzard (Apr 21 2020 at 08:24):

Nam said:

i also tried {(pre : list ℕ) × (suf : list ℕ) // pre++suf = input}

× is for putting the types together, not the terms.

view this post on Zulip Anas Himmi (Apr 21 2020 at 18:05):

in data/set.lean there is this code:

protected def subset (s₁ s₂ : set α) :=
     a⦄, a  s₁  a  s₂

what does ⦃⦄ mean?

view this post on Zulip Bryan Gin-ge Chen (Apr 21 2020 at 18:09):

I forget what these are officially called, but see https://leanprover.github.io/theorem_proving_in_lean/interacting_with_lean.html#more-on-implicit-arguments

view this post on Zulip Anas Himmi (Apr 21 2020 at 18:10):

thank you!

view this post on Zulip Nam (Apr 21 2020 at 23:02):

@Kenny Lau insertion sort with design contract at the insert helper.

inductive sorted : list  -> Prop
| nil {} : sorted []
| one {x : } : sorted [x]
| other {x y : } {tail : list } (h_i: x <= y) (hs : sorted (y :: tail)) : sorted (x :: y :: tail)

lemma tail_of_sorted {hd tl} (h_i : sorted (hd::tl)) : sorted tl :=
by {cases h_i, constructor, assumption}

lemma aux {head n : } {pre suf : list }
    (h1 : sorted (head::(pre++suf))) (h2 : sorted (pre++n::suf)) (h3 : head <= n)
    : sorted (head::pre++n::suf) :=
begin
  cases pre,
  case list.nil { apply sorted.other h3 h2 },
  case list.cons {
    cases h1 with _ _ _ _ head_lte_pre_hd,
    exact sorted.other head_lte_pre_hd h2,
  },
end

def insert (n : ) :
    Π (i : list ), sorted i  {p : list  × list  // p.1 ++ p.2 = i /\ sorted (p.1 ++ n :: p.2)}
| [] h_i := ([], []), begin split, refl, apply sorted.one end
| (head::tail) h_i :=
  if h_n : n  head then
    ([], head::tail),
      begin
        split, refl, apply sorted.other h_n h_i
      end
  else
    let o_rec := insert tail (tail_of_sorted h_i) in
    ([head] ++ o_rec.1.1, o_rec.1.2),
      begin
        split,
        {simp, apply o_rec.2.1},
        {
          simp,
          exact aux (by {rewrite  o_rec.2.1 at h_i, assumption}) o_rec.2.2 (le_of_not_le h_n)}
      end

def sort : list  -> {o : list  // sorted o}
| [] := [], sorted.nil
| [x] := [x], sorted.one
| (head::tail) :=
  let sorted_tail := sort tail in
    let pre_suf := insert head sorted_tail.val sorted_tail.property in
      pre_suf.val.1 ++ head :: pre_suf.val.2, pre_suf.property.2

#eval (sort [3, 4, 1, 5, 2, 1]).1 -- [1, 1, 2, 3, 4, 5]

view this post on Zulip Nam (Apr 21 2020 at 23:12):

reviews are much appreciated ;)

view this post on Zulip Kevin Buzzard (Apr 21 2020 at 23:18):

Well done :-)

view this post on Zulip Nam (Apr 21 2020 at 23:23):

double the amount of code than the other approach. i don't understand why though. i suspect the other approach could cases the insert function, while this approach cannot because it is being defined.

view this post on Zulip Nam (Apr 21 2020 at 23:25):

(i.e. it cannot introspect its own incomplete definition)

view this post on Zulip Frank Dai (Apr 22 2020 at 10:07):

Hello, I have a hypothesis of the form n : \N and h : n < 0. What's a way I can extract false from this?

view this post on Zulip Mario Carneiro (Apr 22 2020 at 10:08):

nat.not_lt_zero _ h

view this post on Zulip Kenny Lau (Apr 22 2020 at 10:09):

cases h

view this post on Zulip Shing Tak Lam (Apr 22 2020 at 12:03):

Is there a way to rename the hypothesis introduced by interval_cases? When I use it it creates a hypothesis called h_1 and I'd like to name it something else.

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 12:06):

Maybe now's the time to learn some basic metaprogramming Shing :-)

view this post on Zulip Shing Tak Lam (Apr 22 2020 at 12:13):

Perhaps, digging into it I think I know where the automatically generated name is coming from, which is a call to note_anon. Since I had a hypothesis h already, it uses h_1. So I don't think I can do much without significant changes :(

and the way that renaming hypothesis is done for other tactics (with ...) means changing the parser as well. So I definitely don't know enough. My knowledge of parsers ends at the very basic BNF from A Level CS.

view this post on Zulip Shing Tak Lam (Apr 22 2020 at 12:14):

I guess rename exists if I cared enough.

view this post on Zulip Reid Barton (Apr 22 2020 at 12:33):

You don't need to do any parser implementation. The allowed syntax for a tactic is encoded into its type in a neat way.

view this post on Zulip Shing Tak Lam (Apr 22 2020 at 12:42):

I see. Looking at it now it does seem to be that way. I would have to figure out how parse worked. It does seem fairly straightforward (at least for something basic) from what I can tell, and there are plenty of other tactics that I could take a look at. Although I don't have much time right now to dig into this further at the moment.

view this post on Zulip AMM (Apr 22 2020 at 14:42):

how do I set up a proof in lean that takes (first assumes) Σ∪{α} proves β (with a sorry maybe), then show Σ proves (α→β) (as a second proof)? (yes, proving the deduction theorem).

view this post on Zulip Kenny Lau (Apr 22 2020 at 14:47):

first define "proves"

view this post on Zulip Mario Carneiro (Apr 22 2020 at 14:51):

\lam, or intro

view this post on Zulip Mario Carneiro (Apr 22 2020 at 14:54):

example {Sigma α β} (s : Sigma) : α  β :=
begin
  intro a,
  -- |- β
  sorry
end

view this post on Zulip AMM (Apr 22 2020 at 14:55):

Kenny Lau said:

first define "proves"

Just the usual first order def that it's the formula that is either an axiom or is obtained from applying rules of inference to previous formulae

view this post on Zulip Kenny Lau (Apr 22 2020 at 14:56):

define it in Lean

view this post on Zulip Kenny Lau (Apr 22 2020 at 14:56):

not define it here

view this post on Zulip AMM (Apr 22 2020 at 14:56):

haha yes okay

view this post on Zulip AMM (Apr 22 2020 at 14:56):

Mario Carneiro said:

\lam, or intro

okay cool!

view this post on Zulip AMM (Apr 22 2020 at 14:57):

what does {Sigma α β} notation mean sorry? and then s is of type sigma?

view this post on Zulip Mario Carneiro (Apr 22 2020 at 14:59):

I assume by Sigma you mean you have some additional assumptions. For the example it doesn't really matter what they are

view this post on Zulip Mario Carneiro (Apr 22 2020 at 14:59):

{Sigma α β} is the same as {Sigma : Sort*} {α : Sort*} {β : Sort*}, it's a bunch of type variables

view this post on Zulip Kenny Lau (Apr 22 2020 at 15:02):

@Mario Carneiro I don't think that's what they mean...

view this post on Zulip Kenny Lau (Apr 22 2020 at 15:03):

@AMM are you trying to formalize the theory of first order logic?

view this post on Zulip Reid Barton (Apr 22 2020 at 15:03):

I think it probably is what they mean but it's worth being explicit about what we are doing here.

view this post on Zulip AMM (Apr 22 2020 at 15:11):

Mario Carneiro said:

I assume by Sigma you mean you have some additional assumptions. For the example it doesn't really matter what they are

yes, a set of formulae (assumptions)

view this post on Zulip AMM (Apr 22 2020 at 15:12):

Mario Carneiro said:

{Sigma α β} is the same as {Sigma : Sort*} {α : Sort*} {β : Sort*}, it's a bunch of type variables

okay that's useful to know

view this post on Zulip AMM (Apr 22 2020 at 15:14):

Kenny Lau said:

AMM are you trying to formalize the theory of first order logic?

I was wanting, as a smaller exercise, to give a brief lean argument as to why the deduction theorem holds, and yes this would be in that context of first order logic.

[Im sure mathlib already has this (any pointers to finding the deduction theorem in mathlib?), and if not other project have for sure used all these first order results, like for flypitch]

view this post on Zulip AMM (Apr 22 2020 at 15:32):

Feels appropriate to be posting this in the noob thread because I'm sure the syntax is horrible, hope I'm not making people lose their patience. How do I fix my definition that I could later use it on the part:

example {Sigma α β} (s : Sigma) : α  β :=

definition:

def proof_of_β {Sigma α β} (s: Sigma) : β :=
--something that captures s has type sigma union alpha not just sigma [probably not possible in type theory?]
sorry

view this post on Zulip Reid Barton (Apr 22 2020 at 15:36):

mathlib doesn't have a formalization of first-order logic, so it doesn't have the deduction theorem.

view this post on Zulip Matt Earnshaw (Apr 22 2020 at 15:37):

similarly flypitch's version of FOL uses natural deduction, so there is no deduction theorem, it is just a given rule namely implication introduction (just as in Lean's logical framework, or as in simply typed lambda calculus where it corresponds to lambda abstraction)
cf. https://github.com/flypitch/flypitch/blob/master/src/fol.lean#L818

view this post on Zulip AMM (Apr 22 2020 at 15:37):

Matt Earnshaw said:

similarly flypitch's version of FOL uses natural deduction, so there is no deduction theorem, it is just a given rule namely implication introduction (just as in Lean's logical framework, or as in simply typed lambda calculus where it corresponds to lambda abstraction)
cf. https://github.com/flypitch/flypitch/blob/master/src/fol.lean#L818

interesting!

view this post on Zulip Kenny Lau (Apr 22 2020 at 15:38):

even if Lean used first order logic, the deduction theorem is a meta theorem, so you wouldn't be table to prove it (or even formalize it) in Lean

view this post on Zulip Kenny Lau (Apr 22 2020 at 15:38):

so if you want to "prove deduction theorem in Lean", you first need to create a subsystem inside Lean, i.e. formalize first order logic inside Lean

view this post on Zulip Kenny Lau (Apr 22 2020 at 15:39):

and then the deduction theorem will be a meta-theorem in the sub-system, i.e. a theorem

view this post on Zulip Reid Barton (Apr 22 2020 at 15:41):

And, it would be a theorem about whatever specific logical system you formalized.

view this post on Zulip AMM (Apr 22 2020 at 15:44):

Kenny Lau said:

and then the deduction theorem will be a meta-theorem in the sub-system, i.e. a theorem

I see, this is a fair point about the metatheorem.
yet the idea that if you take any two things that prove a third thing and, then, only had the first thing and used the previous result to get the conditional involving the second and third would seem very much in the spirit of the deduction theorem.

view this post on Zulip AMM (Apr 22 2020 at 15:45):

Also this other thing pseudo deduction theorem seems like it should be almost trivial in lean without first formalising first order logic. Is my reasoning wrong?

view this post on Zulip Reid Barton (Apr 22 2020 at 15:50):

Do you consider what Mario posted earlier to be an answer?

view this post on Zulip Reid Barton (Apr 22 2020 at 15:53):

Namely, before intro the goal ends with

s : Sigma
 α  β

and after intro the goal ends with

s : Sigma,
a : α
 β

which means if we have a proof of β from Sigma and α, we could stick intro before it to get a proof of α → β from Sigma.

view this post on Zulip AMM (Apr 22 2020 at 16:04):

yes I think for my informal purposes Mario's comment would be an answer!

view this post on Zulip AMM (Apr 22 2020 at 16:06):

is there any way of writing in lean ' we have a proof of β from Sigma and α' in a def before that with a sorry? Otherwise, I guess I can just use English

view this post on Zulip Ashwin Iyengar (Apr 22 2020 at 16:20):

Hi:

import ring_theory.ideals

universe u

variables {R : Type u} [nonzero_comm_ring R]

def S : set R := {r | r = 0}

def x (r : R) (s : R) [h1: r  (S : set R)] [h2: s  (S : set R)] : r = s :=
begin
  rw h1,
end

(this is a bit contrived, but illustrates my confusion) Gives me the error

rewrite tactic failed, lemma is not an equality nor a iff
state:
R : Type u,
_inst_1 : nonzero_comm_ring R,
r s : R,
h1 : r  S,
h2 : s  S
 r = s

Am I incorrect in assuming that h1 is definitionally equivalent to the hypothesis s = 0 ?

view this post on Zulip Ashwin Iyengar (Apr 22 2020 at 16:20):

Sorry i mean r=0

view this post on Zulip Kenny Lau (Apr 22 2020 at 16:21):

rw (show r = 0, from h1)

view this post on Zulip Reid Barton (Apr 22 2020 at 16:22):

You are not wrong about this, however rw wants to see something that's syntactically an equality or iff.

view this post on Zulip Ashwin Iyengar (Apr 22 2020 at 16:23):

Oh ok. Is there another, better tactic to use besides rw? Or is @Kenny Lau's solution the best one?

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:19):

def x (r : R) (s : R) (h1: r  (S : set R)) (h2: s  (S : set R)) : r = s :=
begin
  exact eq.trans h1 h2.symm
end

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:19):

rw only works up to syntactic equality, whereas many other things (e.g. term mode) work up to definitional equality.

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:25):

(and you don't want the h_i in square brackets)

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:27):

def x (r : R) (s : R) (h1: r  (S : set R)) (h2: s  (S : set R)) : r = s :=
begin
  change r = 0 at h1,
  rw h1,
  exact h2.symm -- h2 has type eq _ _ so h2.symm means eq.symm h2
end

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:28):

def x (r : R) (s : R) (h1: r  (S : set R)) (h2: s  (S : set R)) : r = s :=
begin
  unfold has_mem.mem set.mem S set_of at h1,
  rw h1,
  exact h2.symm
end

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:28):

(you can see what to unfold if you write set_option pp.notation false)

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:30):

set_option pp.notation false
def x (r : R) (s : R) (h1: r  (S : set R)) (h2: s  (S : set R)) : r = s :=
begin
  unfold has_mem.mem at h1, -- h1 : set.mem r S
  unfold set.mem at h1, -- h1 : S r
  unfold S at h1, -- h1 : set_of (λ (r : R), eq r 0) r
  unfold set_of at h1, -- h1 : eq r 0
  rw h1,
  exact h2.symm
end

view this post on Zulip Kevin Buzzard (Apr 22 2020 at 17:30):

def x (r : R) (s : R) (h1: r  (S : set R)) (h2: s  (S : set R)) : r = s :=
eq.trans h1 h2.symm

view this post on Zulip Kenny Lau (Apr 22 2020 at 17:31):

def x (r : R) (s : R) [h1: r  (S : set R)] [h2: s  (S : set R)] : r = s :=
begin
  cases h1, cases h2, refl
end

view this post on Zulip Kenny Lau (Apr 22 2020 at 17:31):

also it's a theorem not a def

view this post on Zulip Nam (Apr 22 2020 at 23:53):

how do i get a "decidable" version of {a : Type} [has_le a]? it looks like has_decidable_le is only for list.

view this post on Zulip Mario Carneiro (Apr 23 2020 at 00:07):

[decidable_rel ((≤):a->a->Prop)]

view this post on Zulip Nam (Apr 23 2020 at 00:09):

i tried with a.has_le.le :'(

view this post on Zulip Nam (Apr 23 2020 at 00:09):

{α : Type} [has_le α] [decidable_rel α.has_le.le]

view this post on Zulip Nam (Apr 23 2020 at 00:09):

why does that not work?

view this post on Zulip Mario Carneiro (Apr 23 2020 at 00:16):

this notation α.has_le.le doesn't work

view this post on Zulip Mario Carneiro (Apr 23 2020 at 00:16):

you can write @has_le.le α _ if you don't like the type ascription way (which is I think more readable)

view this post on Zulip Nam (Apr 23 2020 at 00:46):

{α : Type} [has_le α] [decidable_rel (@has_le.le α _)] is certainly more readable. thank you!

view this post on Zulip Mario Carneiro (Apr 23 2020 at 00:47):

What's wrong with using [decidable_rel ((≤):a->a->Prop)] instead? (this is the one I was saying was more readable)

view this post on Zulip Nam (Apr 23 2020 at 00:48):

too many symbols.

view this post on Zulip Scott Morrison (Apr 23 2020 at 01:08):

(I think Mario's is much more readable, for what it's worth.)

view this post on Zulip Nam (Apr 23 2020 at 01:10):

i can see why that style is more prevalent in the repo now :-D

view this post on Zulip Shing Tak Lam (Apr 23 2020 at 01:13):

How should I pattern match on ℕ+? since the way I'd expect doesn't work

def star : ℕ+  ℕ+  ℕ+
| 1 n := n + 1 -- error

view this post on Zulip Bryan Gin-ge Chen (Apr 23 2020 at 02:15):

My instinct would be to do this:

import tactic

def star : ℕ+  ℕ+  ℕ+
| 1, h1 n, hn := n + 1, by linarith
| n1, hn1 n2, hn2 := sorry

view this post on Zulip Shing Tak Lam (Apr 23 2020 at 02:15):

Ok thank you. I'll give that a shot.

view this post on Zulip AMM (Apr 24 2020 at 16:37):

Hello everyone! How would you say Lean compares to other theorem provers? In particular, what would you say are its main virtues?

view this post on Zulip Nam (Apr 24 2020 at 17:42):

@AMM https://jiggerwit.wordpress.com/2018/09/18/a-review-of-the-lean-theorem-prover/

view this post on Zulip Nam (Apr 24 2020 at 17:42):

2018 though.

view this post on Zulip Johan Commelin (Apr 24 2020 at 17:46):

It only got better...

view this post on Zulip Johan Commelin (Apr 24 2020 at 17:46):

@AMM What are you looking for? A comparison can be really long. Is there some specific thing you care about?

view this post on Zulip Johan Commelin (Apr 24 2020 at 17:46):

Do you care about some kind of maths? Or more about software verification? Or something else?

view this post on Zulip Johan Commelin (Apr 24 2020 at 17:46):

Do you care about type theory, or not at all?

view this post on Zulip Nam (Apr 24 2020 at 17:53):

i care mainly about software verification. what other languages should i look into?

view this post on Zulip Johan Commelin (Apr 24 2020 at 18:17):

Coq has a lot on that. And then there are others that I know very little about, like TLA+ and such

view this post on Zulip Sayantan Majumdar (Apr 24 2020 at 18:27):

I was trying the nat.below and nat.brec_on things. I am having some trouble prooving a few things not sure how to go about doing these

def fib1 :   
    | 0 := 1
    | 1 := 1
    | (n + 2) := fib1 (n + 1) + fib1 n

    def fib2 :    :=
        assume n : ,
        @nat.brec_on (λ n : , ) n
        (
            assume n : ,
            assume h : nat.below (λ n : , ) n,
            (
                λ (n : ) (h : nat.below (λ n : , ) n),
                (@nat.cases_on (λ n : , nat.below (λ n : , ) n  ) n
                (λ h : nat.below (λ n : , ) 0, 1)
                (
                    assume n : ,
                    assume h : nat.below (λ n : , ) (nat.succ n),
                    (@nat.cases_on (λ n : , nat.below (λ n : , ) (nat.succ n)  ) n
                    (λ h : nat.below (λ n : , ) 1, 1)
                    (
                        assume n : ,
                        assume h : nat.below (λ n : , ) (nat.succ (nat.succ n)),
                        (h.fst.fst + h.fst.snd.fst.fst)
                    )) h
                )) h
            ) n h
        )

    #reduce fib1 0
    #reduce fib1 1
    #reduce fib1 2
    #reduce fib1 3
    #reduce fib1 4
    #reduce fib1 5
    #reduce fib1 7

    #reduce fib2 0
    #reduce fib2 1
    #reduce fib2 2
    #reduce fib2 3
    #reduce fib2 4
    #reduce fib2 5
    #reduce fib2 7

    example :  n : , fib1 n = fib2 n
    | 0 := rfl
    | 1 := rfl
    | (n + 2) := by rw [fib1, fib2]

view this post on Zulip Sayantan Majumdar (Apr 24 2020 at 18:28):

The last part (n + 2) := sorry case

view this post on Zulip AMM (Apr 24 2020 at 18:43):

Johan Commelin said:

AMM What are you looking for? A comparison can be really long. Is there some specific thing you care about?

Ill have a look at that review, also just the system description was quite helpful. I just wanted some thoughts, this is great!

view this post on Zulip Aniruddh Agarwal (Apr 24 2020 at 20:36):

What's the difference between bundled x and unbundled x in mathlib?

view this post on Zulip Patrick Massot (Apr 24 2020 at 20:39):

This is explained in Section 4.1.1 of https://arxiv.org/abs/1910.09336

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 20:47):

@AMM I think https://artagnon.com/articles/leancoq does a good job of comparing Lean and Coq. In particular, I learnt from this article that Lean breaks "good type theoretic properties like strong normalization, subject reduction, and canonicity", and I have heard from Coq people that this is a big deal for some, but as a mathematician this breakage has never bothered me in the slightest. Another big difference is that "generic mathematicians" use Lean (people who do not specialise in type theory or higher categories or whatever -- they are just number theorists or analysts or geometers or topologists) -- and for me this is another of the main attractions.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 20:47):

@AMM (sorry, didn't work first time)

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 20:53):

@Sayantan Majumdar

    example :  n : , fib1 n = fib2 n
    | 0 := rfl
    | 1 := rfl
    | (n + 2) := begin
     rw [fib1, fib2, _example n, _example (nat.succ n)],
     refl,
    end

view this post on Zulip Michael Barz (Apr 24 2020 at 20:54):

I'm trying to learn lean at the moment by formalizing a few statements about lattices to get a feel for proving things. I was having two difficulties.

At the moment, I have a list of easy theorems about lattices with a closure operator I'd like to try writing up in Lean. From the source code in order.lattice, I decided to define `class closed_lattice (P : Type u) extends lattice P' to be a structure obeying four properties (has a closure function + 3 axioms of closure).

With the very first theorem on my list, I encountered a difficulty: If I want to prove a result about finite lattices with closure operator, how do I add finiteness as a hypothesis to a theorem?

view this post on Zulip Reid Barton (Apr 24 2020 at 20:55):

Probably by adding [fintype P] in the list of arguments somewhere

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 20:56):

Close code quoting with ` (the same character as opening it). And post full working code if you want more precise answers.

view this post on Zulip Michael Barz (Apr 24 2020 at 21:00):

Thank you Reid, that seems to have worked! Sorry about the lack of code--Reid's answer seems to be enough to work at the moment, though I'll be sure to include actual code snippets if I have future questions.

view this post on Zulip Scott Guest (Apr 24 2020 at 22:06):

Hi, I'm new to Lean and wanted to get my feet wet proving some basic things in ZFC, but I'm struggling to actually make use of set_theory.ZFC. Could someone give me guidance on how I would formalize even the statement of something like "If S is a singleton and A is any set, then |S x A| = |A|"?

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:07):

You know that you could just prove that in type theory and not worry about the ZFC stuff?

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:07):

i.e. if S is a singleton and A is any type, then |S x A| = |A|

view this post on Zulip Reid Barton (Apr 24 2020 at 22:10):

Where |A| is cardinal.mk A, from set_theory.cardinal; unrelated to set_theory.zfc.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:10):

It says localized "notation # := cardinal.mk" in cardinal in that file.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:11):

What does that mean?

view this post on Zulip Scott Guest (Apr 24 2020 at 22:11):

I'm taking a set theory course right now which works in ZFC, so I would like to actually formalize it in Lean's model of ZFC if possible. However, I guess this is also something I'm a little unclear on: what exactly would it look like to phrase this just in type theory versus in ZFC?

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:11):

Because a type is just a beefed-up set, you would never notice the difference if you proved it in type theory.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:12):

import set_theory.cardinal

example (S A : Type) : cardinal.mk S = 1  cardinal.mk (S × A) = cardinal.mk A :=
sorry

I guess that's the type theory version

view this post on Zulip Reid Barton (Apr 24 2020 at 22:12):

Even if you formalize it as a theorem about the model of ZFC in mathlib, if you prove it, you are not using the axioms of ZFC but rather the "metatheory" (Lean).

view this post on Zulip Reid Barton (Apr 24 2020 at 22:14):

And in particular you wouldn't know whether it holds in other models of ZFC.

view this post on Zulip Scott Guest (Apr 24 2020 at 22:16):

Thank you, that makes sense. If I want to prove theorems about any model of ZFC then, is there a way to actually do this in Lean, or should I just stick to proving the analogous statements with types?

view this post on Zulip Reid Barton (Apr 24 2020 at 22:17):

You can check out https://github.com/flypitch/flypitch/, but maybe it would be more ergonomic to use a theorem prover based on ZFC.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:18):

If there's a bijection between two sets then they have the same cardinality.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:19):

So it would suffice to prove that there's a bijection between AA and S×AS\times A, and that would be a rather pleasant beginner exercise in Lean, and the proof would be exactly the same as the set theory proof.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:22):

import data.equiv.basic -- theory of bijections

variables {S A : Type} (s : S) (hs :  t : S, s = t)

include hs

def one_way : S × A  A := sorry

def other_way : A  S × A := sorry

def they_biject : S × A  A :=
{ to_fun := one_way s hs,
  inv_fun := other_way s hs,
  left_inv := sorry,
  right_inv := sorry }

view this post on Zulip Scott Guest (Apr 24 2020 at 22:26):

Got it, it's clear now. I definitely have a lot to learn about Lean, thank you for being so willing to help new users!

view this post on Zulip Michael Barz (Apr 24 2020 at 22:26):

Hello again! I have one more question about finiteness. Reid's [fintype P] solution has worked well for me to use finiteness as a hypothesis in a theorem, although I've encountered difficulties with a related problem. Below is some code trying to express the idea that "any two suitable sets M and N have the same number of elements" (in the code, lattice is just the standard mathlib order.lattice)

import order.lattice
import data.fintype.basic

def is_totally_ordered (P : Type u) [lattice P] (M : set P) := ( m : M,  n : M, m  n  n  m)
def is_maximal (P : Type u) [lattice P] (M : set P) := ( p : P,  m : M, (p  m  p  m)  p  M)
def is_chain (P : Type u) [lattice P] (M : set P) := is_totally_ordered P M  is_maximal P M


class chain_condition (P : Type u) extends lattice P :=
(finite_chains :  M : set P, (is_totally_ordered P M  fintype M))
(chains_equal_length :  M N : set P, ((is_chain P M  is_chain P N  fintype M  fintype N)  (fintype.elems M).card = (fintype.elems N).card))
(max_elm :  M : P, (forall q : P, q  M))
(min_elm :  m : P, (forall q : P, m  q))

The main issue I'm having is with the second axiom--what I wrote errors in Lean (specifically at the last \and in the condition, with a somewhat long error message I could reproduce if needed), and I suspect because while [fintype M] is the right way of asserting M is finite in a hypothesis of a theorem, what I'm doing is the wrong way of asserting the finiteness of M in this implication.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:27):

What imports do I need?

view this post on Zulip Michael Barz (Apr 24 2020 at 22:27):

import order.lattice

view this post on Zulip Michael Barz (Apr 24 2020 at 22:27):

import data.fintype.basic too, sorry!

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:27):

Why not edit the code to make it work out of the box?

view this post on Zulip Michael Barz (Apr 24 2020 at 22:28):

Oh, sure

view this post on Zulip Michael Barz (Apr 24 2020 at 22:28):

It's edited with imports now, sorry about that!

view this post on Zulip Scott Morrison (Apr 24 2020 at 22:29):

(Although note that for any "content-ful" edits, people usually prefer if you just post a new copy of the MWE, so it doesn't screw up the conversation history.)

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:29):

fintype M is probably not what you want. It's data, not a proposition.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:29):

Because M : set P you might want to instead use M : finset P, the type of finite subsets of P. This would solve your problems immediately.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:30):

Then you could just drop fintype M completely.

view this post on Zulip Michael Barz (Apr 24 2020 at 22:30):

Oh, thank you!
For future reference though, how would I get a proposition asserting that M is a fintype?

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:31):

For M : set P, if you want to conclude "M is finite" then set.finite M is the way to go.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:31):

(import data.set.finite)

view this post on Zulip Michael Barz (Apr 24 2020 at 22:32):

Thank you!

I think I will end up going with the set.finite M route, since implementing the M : finset P approach errors that is_chain is defined on types M : set P, not for M : finset P

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 22:34):

I am not immediately sure how to start making assertions about the cardinality of a finite set though :-/

view this post on Zulip Michael Barz (Apr 24 2020 at 22:36):

Ah, I do not either. However, I figured out that changing the is_chain to work on \u M instead of M has lean recognize that finsets are still sets, and so the is_chain definition and M.card both work

view this post on Zulip Reid Barton (Apr 24 2020 at 22:36):

I think there's a nat-valued cardinality function somewhere that returns 0 for infinite sets

view this post on Zulip Scott Guest (Apr 24 2020 at 23:14):

Hello again, I had a few more questions about working with sets. As discussed a bit ago, I see how statements analogous to "If S is a singleton and A is a set, then |S x A| = |A|" can be formalized by letting S A : Type, but I don't see how to extend this to more complicated statements.

Namely, say I wanted to prove "For any sets X and Y, there is some set Z with |X| = |Z| and Z ∩ Y = ∅." Unless I missed something, it seems like types in Lean don't support intersection, so I don't know how to specify the disjointness part. The statement also isn't true in general if I assume X Y : set U for some fixed type U, say because U could be finite with Y containing every element of U. Any advice?

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 23:27):

This is the sort of question which you have to deal with in set theory but which typically you don't ever need to worry about in type theory.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 23:28):

This is some sort of fiddly foundational thing which sometimes comes up in set theory. Why would you ever need that in practice?

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 23:31):

Type theory is different to set theory. It's more powerful. A "bare type" is just like a set, but if T is a type then a term t : T of type T isn't like a set -- t is more like an "atom". This is a good thing, because if G is a group then in set theory the elements of G are also sets, but they are sets whose elements are irrelevant and never talked about by mathematicians. So letting G be a type is actually a better model for groups. However, if S and T are two distinct types and you have terms s : S and t : T then it does not even make sense to ask if s = t. This is much more disconcerting for someone used to set-theoretic mathematics.

view this post on Zulip Scott Guest (Apr 24 2020 at 23:37):

Ah, I had a hunch I was generally barking up the wrong tree trying to do this type of thing. Eventually, I wanted to formalize Tarksi's proof that choice is equivalent over ZF to the statement "For all infinite A, |A x A| = |A|", and it's needed for a line in that, so this is indeed a fiddly foundation thing.

view this post on Zulip Kevin Buzzard (Apr 24 2020 at 23:41):

In Lean, A×AA\times A and AA will automatically be "disjoint", if that helps.

view this post on Zulip Scott Guest (Apr 24 2020 at 23:42):

I need disjointness between some set and it's Hartogs number, but since those are different types it seems I get that for free. Thank you again.

view this post on Zulip Nam (Apr 25 2020 at 00:34):

does anyone know of a sample big-O analysis in Lean?

view this post on Zulip Reid Barton (Apr 25 2020 at 01:04):

Of an algorithm?

view this post on Zulip Mario Carneiro (Apr 25 2020 at 01:09):

@Scott Guest The statement "For all infinite A, |A x A| = |A|" is perfectly reasonable in type theory, and you can prove it without having to assume ZFC foundations. However, proving an equivalence with choice is going to be tough because lean assumes choice all over the place, so proofs in "ZF" are not at all nice.

view this post on Zulip Nam (Apr 25 2020 at 01:50):

Reid Barton said:

Of an algorithm?

yes, of an algorithm, preferably some well-known one.

view this post on Zulip Mario Carneiro (Apr 25 2020 at 01:51):

There is the big-O symbol, but runtime analysis of algorithms is not lean's strong suit. The usual way we represent algorithms, as functions, precludes the ability to measure the time complexity of the algorithm, so you need some other mechanism like a step counting monad

view this post on Zulip Shing Tak Lam (Apr 25 2020 at 01:53):

I guess there's this? Might be more to do with Rust not Lean though. I'm not sure tbh.

https://github.com/Kha/electrolysis

(Last section of the linked thesis)

view this post on Zulip Andrew Ashworth (Apr 25 2020 at 01:59):

Let me plug Verified Functional Algorithms here: https://softwarefoundations.cis.upenn.edu/current/vfa-current/index.html

view this post on Zulip Andrew Ashworth (Apr 25 2020 at 02:04):

The author says this about runtime calculations:

"3. There's no notion of "run time" in Coq. That is, we can't say what it means that a Coq function "takes N steps to evaluate." Therefore, we can't prove that binary search trees are efficient. - SOLUTION 1: Don't prove (in Coq) that they're efficient; just prove that they are correct. Prove things about their efficiency the old-fashioned way, on pencil and paper. - SOLUTION 2: Prove in Coq some facts about the height of the trees, which have direct bearing on their efficiency. We'll explore that in later chapters."

view this post on Zulip Andrew Ashworth (Apr 25 2020 at 02:07):

and here's a stackexchange post on the topic: https://cstheory.stackexchange.com/questions/38818/proving-running-time-upper-bounds-for-algorithms-in-dependent-type-theory

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 25 2020 at 02:10):

Is there a preferred way to express divisibility? Looking through mathlib/other posts I'm seeing it expressed in many different equivalent forms depending on the context. Mathematically this doesn't bother me, but it seems like having multiple definitions for things is discouraged in computer science land?

view this post on Zulip Nam (Apr 25 2020 at 02:12):

can't users (we) guide Lean / Coq with some assumptions / hints?

view this post on Zulip Nam (Apr 25 2020 at 02:13):

e.g. this part / line takes one instruction

view this post on Zulip Nam (Apr 25 2020 at 02:14):

i guess that's what Mario referred to as steps monad/

view this post on Zulip Mario Carneiro (Apr 25 2020 at 02:14):

@Nam First you have to define what it means for something to take time

view this post on Zulip Mario Carneiro (Apr 25 2020 at 02:16):

Ideally, we would want (\lam x, e1) e2 ~> [e2/x] e1 to take some time, it is a complicated operation after all, but to lean they are equal and so no function can distinguish them

view this post on Zulip Mario Carneiro (Apr 25 2020 at 02:24):

Here's an example of using a step counting monad to prove time bounds:

import data.list.basic

def step (α : Type) := α × 

def step.time {α} (x : step α) :  := x.2

instance : monad step :=
{ pure := λ α a, (a, 0),
  bind := λ α β x f, ((f x.1).1, x.2 + (f x.1).2) }

def delay (n : ) : step unit := ((), n)

def tick : step unit := delay 1

def addM (m n : ) : step  :=
(m + n, nat.size m + nat.size n)

def mulM (m n : ) : step  :=
(m * n, nat.size m * nat.size n)

def sumM : list   step 
| [] := pure 0
| (a::l) := sumM l >>= addM a

theorem sum_correct :  l, (sumM l).1 = l.sum  := sorry
theorem sum_time :  l, (sumM l).time  2 * (l.map nat.size).sum := sorry

view this post on Zulip Nam (Apr 25 2020 at 02:41):

thanks! that's very useful.

view this post on Zulip Kenny Lau (Apr 25 2020 at 04:02):

@Scott Guest you can formalize what it means to be a model of ZFC, then you can work in a general model of ZFC if you want

view this post on Zulip Kenny Lau (Apr 25 2020 at 04:02):

remember to show that the "standard" model in mathlib is indeed a model of ZFC

view this post on Zulip Kenny Lau (Apr 25 2020 at 04:03):

This is actually something I want to do once I have more time

view this post on Zulip Kevin Buzzard (Apr 25 2020 at 08:54):

ROCKY KAMEN-RUBIO said:

Is there a preferred way to express divisibility? Looking through mathlib/other posts I'm seeing it expressed in many different equivalent forms depending on the context. Mathematically this doesn't bother me, but it seems like having multiple definitions for things is discouraged in computer science land?

In which type?

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 25 2020 at 18:48):

Kevin Buzzard said:

ROCKY KAMEN-RUBIO said:

Is there a preferred way to express divisibility? Looking through mathlib/other posts I'm seeing it expressed in many different equivalent forms depending on the context. Mathematically this doesn't bother me, but it seems like having multiple definitions for things is discouraged in computer science land?

In which type?

Either nat or int.

view this post on Zulip Kevin Buzzard (Apr 25 2020 at 18:55):

a \| b is what is used for both of those types.

view this post on Zulip Frank Dai (Apr 25 2020 at 19:02):

I have a hypothesis of the form h : f = g, how can I get a hypothesis of the form hx : f x = g x?

view this post on Zulip Kevin Buzzard (Apr 25 2020 at 19:03):

have hx : f x = g x, rw h

view this post on Zulip Kevin Buzzard (Apr 25 2020 at 19:03):

have is a very useful way to make new hypothesis. It creates a new goal, but if the proof is easy then this is no problem.

view this post on Zulip Frank Dai (Apr 25 2020 at 19:04):

is there a way to do it without copying f and g (they're both really long)?

view this post on Zulip Johan Commelin (Apr 25 2020 at 19:04):

The term-mode variant is have hx := congr_fun h x

view this post on Zulip Johan Commelin (Apr 25 2020 at 19:04):

And it doesn't require copying f and g

view this post on Zulip Sam Raleigh (Apr 25 2020 at 19:05):

If I wanted to prove results about graphs in lean, is there a graph type of some kind?

view this post on Zulip Frank Dai (Apr 25 2020 at 19:05):

I prefer ap but I guess that's okay :P

view this post on Zulip Johan Commelin (Apr 25 2020 at 19:09):

Sam Raleigh said:

If I wanted to prove results about graphs in lean, is there a graph type of some kind?

See the hedetniemi branch

view this post on Zulip Johan Commelin (Apr 25 2020 at 19:09):

It's very much work in progress

view this post on Zulip Bryan Gin-ge Chen (Apr 25 2020 at 19:10):

See also the associated Zulip thread.

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 25 2020 at 19:47):

Does Lean have a floor/ceiling function to get from non-negative reals to nats? Looking through mathlib I'm not seeing anything, but my intuition for mathlib's organization and naming conventions still isn't great.

view this post on Zulip Mario Carneiro (Apr 25 2020 at 19:49):

They are in algebra.archimedean

view this post on Zulip Mario Carneiro (Apr 25 2020 at 19:49):

grepping for floor also helps

view this post on Zulip ROCKY KAMEN-RUBIO (Apr 25 2020 at 20:00):

Mario Carneiro said:

They are in algebra.archimedean

Looks like exists_nat_gt coupled with a cases does the job. A little clunky though. I'll keep looking to see if there's a direct function.

view this post on Zulip Chris Hughes (Apr 25 2020 at 20:21):

ceil gives you an int

view this post on Zulip Kevin Buzzard (Apr 25 2020 at 20:35):

I suspect that the precise functions you're asking about aren't there Rocky, you might want to write it yourself. It could take as input a real x and output a natural real.natfloor x, which is 0 if x is negative and the floor otherwise. You'd then have to make a little API for the function so it was usable

view this post on Zulip Mario Carneiro (Apr 25 2020 at 20:41):

You could always use int.to_nat (floor x)

view this post on Zulip Mario Carneiro (Apr 25 2020 at 20:42):

but if cases exists_nat_gt does the job for you, I would actually suggest using that instead, since the floor function is more complicated than that

view this post on Zulip Sam Raleigh (Apr 26 2020 at 01:59):

Given a b c : nat, how do I rewrite a hypothesis of the form a < b as a*c < b*c?

view this post on Zulip Sam Raleigh (Apr 26 2020 at 01:59):

Assuming c > 0 ofc

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 02:01):

Here's one way to find lemmas like this:

import tactic

example (a b c : ) (hc : c > 0) (h : a < b) : a * c < b * c := by library_search
-- Try this: exact mul_lt_mul_of_pos_right h hc

view this post on Zulip Sam Raleigh (Apr 26 2020 at 02:02):

Haha you answered my next question before I could even ask it: how do I find lemmas like this in general?

view this post on Zulip Sam Raleigh (Apr 26 2020 at 02:02):

thanks!

view this post on Zulip Sam Raleigh (Apr 26 2020 at 03:16):

Say I have some hypothesis h : 2^a * (2^(1-b) * c) < 2^1 * 1 and my goal looks like2^(a - b) * c * 2 < 2^a. On paper all you need to do to get from the goal to the hypothesis is rearrange things, but this is proving to be tedious to implement in lean. Is there some automating tactic like ring that would close the goal given h?

view this post on Zulip Sam Raleigh (Apr 26 2020 at 03:17):

I don't suppose there's by library_search for tactics, eh @Bryan Gin-ge Chen ?

view this post on Zulip Shing Tak Lam (Apr 26 2020 at 03:17):

hint

view this post on Zulip Mario Carneiro (Apr 26 2020 at 03:17):

there's no way that theorem is in the library

view this post on Zulip Scott Morrison (Apr 26 2020 at 03:17):

are your variables all int?

view this post on Zulip Sam Raleigh (Apr 26 2020 at 03:18):

oh sorry, I should have specified they are all nat

view this post on Zulip Scott Morrison (Apr 26 2020 at 03:18):

(Shing is saying that the closest thing for library_search for tactics is hint. But it is very primitive, and will get you nowhere here.)

view this post on Zulip Mario Carneiro (Apr 26 2020 at 03:18):

nat subtraction will cause a lot of problems here

view this post on Zulip Scott Morrison (Apr 26 2020 at 03:18):

Your first step should probably be to work with int. :-)

view this post on Zulip Mario Carneiro (Apr 26 2020 at 03:18):

hopefully you know that b is at most 1?

view this post on Zulip Mario Carneiro (Apr 26 2020 at 03:19):

and b <= a

view this post on Zulip Mario Carneiro (Apr 26 2020 at 03:20):

you could also "rearrange things" in lean using calc

view this post on Zulip Sam Raleigh (Apr 26 2020 at 03:25):

@Scott Morrison @Mario Carneiro Thanks, I completely forgot about nats and subtraction.

view this post on Zulip Sam Raleigh (Apr 26 2020 at 03:33):

Now supposing that a b c : int how would I use calc given h? I tried searching the mathlib and core library documentation, but there doesn't appear to be anything on calc in either.

view this post on Zulip Shing Tak Lam (Apr 26 2020 at 03:34):

https://leanprover-community.github.io/mathlib_docs/calc.html

view this post on Zulip Sam Raleigh (Apr 26 2020 at 03:35):

Ah thank you @Shing Tak Lam , I made the mistake of looking only under tactics

view this post on Zulip Johan Commelin (Apr 26 2020 at 03:38):

Shing Tak Lam said:

https://leanprover-community.github.io/mathlib_docs/calc.html

Why don't we get syntax highlighting in these docs?

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 03:42):

I'm planning to look into adding it after the next pygments release which should have the updated Lean syntax highlighting.

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 03:43):

No idea when that will be though...

view this post on Zulip Billy Price (Apr 26 2020 at 04:40):

How do see the fully unpacked version of this term I'm trying to check?

def ex_unique (A : type) (φ : term Ω) : term Ω :=
  ' A $ |{A | φ}|  |{var A 3}|

#check ex_unique 𝟙 

view this post on Zulip Frank Dai (Apr 26 2020 at 04:49):

How do I compute with snd on dependent pairs? Slightly more generally, how do I see what the computation rules for foo_thing are?

def foo : Type 1 := Σ (B : Type), (A  B)

def foo_thing : foo := nat, id

lemma foo_map_is_id : foo_thing.snd = id := sorry

view this post on Zulip Kenny Lau (Apr 26 2020 at 05:10):

variables {A : Type}
def foo : Type 1 := Σ (B : Type), (A  B)

def foo_thing : foo := nat, id
#print prefix foo_thing
-- foo_thing.equations._eqn_1 : foo_thing = ⟨ℕ, id ℕ⟩

lemma foo_map_is_id : foo_thing.snd = id := rfl

view this post on Zulip Kenny Lau (Apr 26 2020 at 05:10):

@Billy Price set_option pp.all true

view this post on Zulip Sam Raleigh (Apr 26 2020 at 07:06):

lemma num_2_cols_Kn_with_monochromatic_Kk_lt_num_2_cols_Kn
    (n k : ) (h : 2^(1 - k.choose(2)) * n.choose(k) < 1) :
    2^(n.choose(2) - k.choose(2)) * 2 * n.choose(k) < 2^(n.choose(2)) :=
calc
    2^(n.choose(2) - k.choose(2)) * 2 * n.choose(k) = 2^(n.choose(k)) * 2^(-(k.choose(2))) * 2 * n.choose(k) :

I'm getting an error on the last line that says

failed to synthesize type class instance for
n k : ℕ,
h : 2 ^ (1 - nat.choose k 2) * nat.choose n k < 1
⊢ has_neg ℕ

Now I know this is likely happening because nat and subtraction aren't playing nicely together and I should switch to k n : int.
My only concern is that int doesn't contain a choose function the way nat does. Should I define my own binomial coefficient that accepts integers? If so, I'd greatly appreciate it if someone could point me towards resources on defining your own functions. Or is there a way I could still use nat.choose with k n : int?

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:08):

how about don't write 2^-k.choose 2

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:08):

because in all interpretations it is just 0

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:08):

instead 2^(nC2-kC2) = 2^(nC2) / 2^(kC2) makes more sense

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:09):

also 2^(1 - k.choose(2)) * n.choose(k) < 1 probably doesn't mean what you think it means

view this post on Zulip Mario Carneiro (Apr 26 2020 at 07:09):

Maybe lift everything to Q

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:10):

right, you can coerce n.choose (k) to \Q

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:10):

without having to define rat.choose

view this post on Zulip Sam Raleigh (Apr 26 2020 at 07:20):

Thanks for your answers. What do you mean by coerce?

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:24):

lemma num_2_cols_Kn_with_monochromatic_Kk_lt_num_2_cols_Kn
    (n k : ) (h : (2^(1 - k.choose(2)) * n.choose(k) : \Q) < 1) :
    (2^(n.choose(2) - k.choose(2)) * 2 * n.choose(k) : \Q) < 2^(n.choose(2)) :=

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:24):

remember to import data.rat.basic

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:25):

oh and you need to coerce the exponents to \Z

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:25):

lemma num_2_cols_Kn_with_monochromatic_Kk_lt_num_2_cols_Kn
    (n k : ) (h : (2^(1 - k.choose(2) : \Z) * n.choose(k) : \Q) < 1) :
    (2^(n.choose(2) - k.choose(2) : \Z) * 2 * n.choose(k) : \Q) < 2^(n.choose(2) : \Z) :=

view this post on Zulip Kenny Lau (Apr 26 2020 at 07:26):

coercion is basically an injection, in this case the injection \N -> \Z

view this post on Zulip Sam Raleigh (Apr 26 2020 at 07:30):

Oh wow I was hoping it was possible to do something just like this. Thanks a bunch : D

view this post on Zulip Apurva Nakade (Apr 26 2020 at 16:23):

What would be a good method to define "a monoidal category which is also a groupoid"?

view this post on Zulip Anas Himmi (Apr 26 2020 at 16:47):

how to show this?

example (s:set (set α)) (h: a, a  s  a = ) : s={}  s= := sorry

view this post on Zulip Kenny Lau (Apr 26 2020 at 16:56):

import tactic

example {α : Type*} (s : set (set α)) (h :  a, a  s  a = ) : s = {}  s =  :=
or.cases_on (set.subsingleton.eq_empty_or_singleton $ λ x hx y hy, (h x hx).trans (h y hy).symm) or.inr $
by { rintro t, rfl, left, rw set.singleton_eq_singleton_iff, exact h t (set.mem_singleton t) }

view this post on Zulip Anas Himmi (Apr 26 2020 at 16:59):

thank you!!

view this post on Zulip Reid Barton (Apr 26 2020 at 17:16):

Apurva Nakade said:

What would be a good method to define "a monoidal category which is also a groupoid"?

variables {C : Type u} [𝒞 : groupoid.{v} C] [monoidal_category C] should do it.

view this post on Zulip Apurva Nakade (Apr 26 2020 at 18:06):

Reid Barton said:

Apurva Nakade said:

What would be a good method to define "a monoidal category which is also a groupoid"?

variables {C : Type u} [𝒞 : groupoid.{v} C] [monoidal_category C] should do it.

Thanks a lot!

view this post on Zulip Sam Raleigh (Apr 26 2020 at 20:43):

@Kenny Lau I added the coercions:

lemma num_2_cols_Kn_with_mono_Kk_lt_num_2_cols_Kn
    (n k : ) (h : (2^(1 - k.choose(2) : ) * n.choose(k) : ) < 1) :
    (2^(n.choose(2) - k.choose(2) : ) * 2 * n.choose(k) : ) < 2^(n.choose(2) : ) :=
calc
    2^(n.choose(2) - k.choose(2)) * 2 * n.choose(k) = 2^(n.choose(2) - k.choose(2)) * 2 * n.choose(k) :
    ...

But I'm still getting this issue:

failed to synthesize type class instance for
n k : ℕ
⊢ has_pow ℚ ℤ

view this post on Zulip Kenny Lau (Apr 26 2020 at 20:44):

you need to import algebra.field_power

view this post on Zulip Sam Raleigh (Apr 26 2020 at 20:45):

Aha! I was wondering why exponentiation didn't seem to be defined for int, thanks

view this post on Zulip Sam Raleigh (Apr 26 2020 at 20:50):

Why do I still get a similar issue for this?
example (a b : ℤ) : 2^(a - b) = 2^a / 2^b :=

view this post on Zulip Sam Raleigh (Apr 26 2020 at 20:51):

failed to synthesize type class instance for
a b : ℤ
⊢ has_pow ℕ ℤ

view this post on Zulip Sam Raleigh (Apr 26 2020 at 20:52):

Is there another import I'm missing?

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 20:52):

Lean thinks the 2s are nats. You might just have to include the coercions explicitly:

example (a b : ) : (2 : )^(a - b) = (2 : )^a / (2 : )^b :=

edit: sorry, you'll want , not for the 2s.

view this post on Zulip Sam Raleigh (Apr 26 2020 at 20:54):

Thanks! How come I didn't get this issue earlier with the exponents involving binomial coefficients?

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 20:54):

I guess it's because Lean was able to correctly infer the rats from the LHS: (2^(n.choose(2) - k.choose(2) : ℤ) * 2 * n.choose(k) : ℚ)

view this post on Zulip Sam Raleigh (Apr 26 2020 at 20:57):

neat, thank you

view this post on Zulip Sam Raleigh (Apr 26 2020 at 21:01):

I'm surprised example (a b : ℤ) : (2 : ℚ)^(a - b) = (2 : ℚ)^a / (2 : ℚ)^b := by library_search turned up nothing. Is there really no theorem for this?

view this post on Zulip Kenny Lau (Apr 26 2020 at 21:03):

#check @fpow_sub
/- fpow_sub :
  ∀ {G₀ : Type u_1} [_inst_1 : group_with_zero G₀] {a : G₀},
    a ≠ 0 → ∀ (z1 z2 : ℤ), a ^ (z1 - z2) = a ^ z1 / a ^ z2
 -/

view this post on Zulip Sam Raleigh (Apr 26 2020 at 21:05):

How come by library_searchdidn't turn this up? How did you find this?

view this post on Zulip Sam Raleigh (Apr 26 2020 at 21:06):

Also what does the ampersand do? Sorry I'm extremely new to this

view this post on Zulip Kenny Lau (Apr 26 2020 at 21:07):

the @ shows all the parameters instead of just the explicit parameters (i.e. the ones you need to specify)

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 21:07):

I guess it doesn't show up in by library_suggest by library_search because you need to convince Lean that 2 ≠ 0. It's the 3rd thing that comes up in by suggest.

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 21:08):

import algebra.field_power

example (a b : ) : (2 : )^(a - b) = (2 : )^a / (2 : )^b :=
fpow_sub dec_trivial a b
-- this also works:
-- fpow_sub two_ne_zero a b

view this post on Zulip Sam Raleigh (Apr 26 2020 at 21:12):

What are the differences between by library_search, by library_suggest and by suggest? I was unaware that the last two existed until now.

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 21:13):

Whoops, library_suggest doesn't exist. That was a typo on my part. You can read more about them in the tactic docs: https://leanprover-community.github.io/mathlib_docs/tactics.html#suggest

view this post on Zulip Sam Raleigh (Apr 26 2020 at 21:13):

thank you!

view this post on Zulip Kevin Buzzard (Apr 26 2020 at 21:19):

library_search finds the exact lemma which will solve your goal. It doesn't know that 2 isn't 0 so it won't be able to solve it. I suspect 0^{a-b}=0^a/0^b is false in general. suggestjust looks for lemmas that look like they might make progress, and doesn't claim to solve the goal in general (indeed you'd be left with the goal 2 \ne 0 if you applied fpow_sub directly).

There is another method though, and although it is a lot harder to master, it is in some sense the most powerful. The method is to learn the conventions used in naming lemmas in the library, and then start to guess what the name of the lemma you are looking for is. For example pow means raising something to a natural power, and fpow means raising something to an integer power. add is addition, sub is subtraction, not to be confused with neg which is unary negation. div is division, not to be confused with dvd, which means "divides" (like 3 divides 6), and so on and so on. After a while you can start predicting theorem names, and then typing a guess and hitting ctrl-space might bring up a list of possibilities, which (possibly after pressing ctrl-space again) you can start to scroll through until you hit the one you want.

view this post on Zulip Bryan Gin-ge Chen (Apr 26 2020 at 21:21):

This mathlib doc might help re: the naming conventions.

view this post on Zulip Brandon Brown (Apr 26 2020 at 22:53):

Looks for some hints for this one.
example : (∃ x, p x) ↔ ¬ (∀ x, ¬ p x) := sorry
My guess is its a longer proof, so just looking for some general guidance. I find proofs involving \not challenging for some reason.
Here's my starting point:

        example : ( x, p x)  ¬ ( x, ¬ p x) :=
            iff.intro
            (
                assume h1,
                match h1 with x, p1 :=
                    by_contradiction
                    (
                        _
                    )
                end
            )
            (
                assume h1,
                _
            )

Which gives me a first goal of
⊢ (¬¬∀ (x : α), ¬p x) → false
and second goal of
⊢ ∃ (x : α), p x

view this post on Zulip Marc Huisinga (Apr 26 2020 at 23:18):

hint: the first direction does not require classical reasoning

view this post on Zulip Kevin Buzzard (Apr 26 2020 at 23:28):

Does finish or tauto! do it?

view this post on Zulip Brandon Brown (Apr 26 2020 at 23:37):

You mean like by finish ? Doesn't seem to work

view this post on Zulip Kevin Buzzard (Apr 26 2020 at 23:39):

not P is by definition P -> false, if this helps

view this post on Zulip Kevin Buzzard (Apr 26 2020 at 23:39):

But these super-verbose term mode proofs are hard to steer

view this post on Zulip Sam Raleigh (Apr 27 2020 at 00:31):

What does "maximum class-instance resolution depth has been reached" mean?

view this post on Zulip Bryan Gin-ge Chen (Apr 27 2020 at 00:36):

@Brandon Brown by finish (or even by simp) works after you import tactic. Here are some hints towards an "honest" (or "tedious" depending on your tastes) term proof:

open classical
variables (α : Type) (x : α) (p : α  Prop)
example : ( x, p x)  ¬ ( x, ¬ p x) :=
    iff.intro
    (
        assume h1 h2,
        exists.elim h1 _
    )
    (
        assume h1,
        by_contradiction (assume h2 : ¬ _, h2 (h1 _).elim)
    )

view this post on Zulip Bryan Gin-ge Chen (Apr 27 2020 at 00:37):

@Sam Raleigh It can mean different things, depending on the state of your code. Sometimes it means you have a bad instance. Sometimes it means that there's some other issue with your code. Can you post a MWE (minimum working example)?

view this post on Zulip Brandon Brown (Apr 27 2020 at 00:46):

thanks @Bryan Gin-ge Chen !

view this post on Zulip Sam Raleigh (Apr 27 2020 at 00:57):

Actually I think I figured it out, thank you Bryan

view this post on Zulip Sam Raleigh (Apr 27 2020 at 00:57):

I am curious as to what you meant by "bad instance" though

view this post on Zulip Bryan Gin-ge Chen (Apr 27 2020 at 01:03):

If you're not careful about the instances you declare, Lean's type class search can get into an infinite loop. I can't come up with an example off the top of my head, but searching Zulip for "type class loop" will pull up a bunch of conversations where these sorts of things get debugged. (If by chance you haven't learned about Lean's type classes yet, here's the relevant section of TPiL).

view this post on Zulip Sam Raleigh (Apr 27 2020 at 01:09):

lemma strict_ineq
    (a b c : )
    (h : (2^(1 - b) * c : ) < 1) :
    (2^(a - b) * 2 * c : ) < 2^a :=
begin
    rw fpow_sub two_ne_zero a b
    --other stuff
end

I don't understand how I am getting the following type mismatch error:

type mismatch at application
fpow_sub two_ne_zero
term
two_ne_zero
has type
2 ≠ 0
but is expected to have type
?m_2 ≠ 0

How are 2 \neq 0 and ?m_2 ≠ 0 a mismatch?

view this post on Zulip Bryan Gin-ge Chen (Apr 27 2020 at 01:19):

Hmm, looks like there's something funky going on with the zero instances:

import data.rat.basic
import algebra.field_power

-- set_option pp.all true
lemma strict_ineq
    (a b c : )
    (h : (2^(1 - b) * c : ) < 1) :
    (2^(a - b) * 2 * c : ) < 2^a :=
begin
    rw [fpow_sub (begin
      convert two_ne_zero,
/-
Tactic State:
4 goals
a b c : ℤ,
h : 2 ^ (1 - b) * ↑c < 1
⊢ no_zero_divisors.to_has_zero ?m_1 = mul_zero_class.to_has_zero ?m_1

a b c : ℤ,
h : 2 ^ (1 - b) * ↑c < 1
⊢ group_with_zero ?m_1

a b c : ℤ,
h : 2 ^ (1 - b) * ↑c < 1
⊢ Type ?

a b c : ℤ,
h : 2 ^ (1 - b) * ↑c < 1
⊢ linear_ordered_semiring ?m_1

-/
    end) a b],
    --other stuff
end

view this post on Zulip Bryan Gin-ge Chen (Apr 27 2020 at 01:34):

This works, but this issue deserves more attention from someone who understands what's going on above:

import data.rat.basic
import algebra.field_power

-- set_option pp.all true
lemma strict_ineq
    (a b c : )
    (h : (2^(1 - b) * c : ) < 1) :
    (2^(a - b) * 2 * c : ) < 2^a :=
begin
    rw [fpow_sub (@two_ne_zero  _) a b],
    -- other stuff
end

view this post on Zulip Mario Carneiro (Apr 27 2020 at 01:51):

rw @fpow_sub ℚ _ _ two_ne_zero a b also works. Think about what the elaborator has to do here. The error happens at fpow_sub two_ne_zero, where

fpow_sub :
   {G₀ : Type u_1} [_inst_1 : group_with_zero G₀] {a : G₀},
    a  0   (z1 z2 : ), a ^ (z1 - z2) = a ^ z1 / a ^ z2
two_ne_zero :  {α : Type u_1} [_inst_1 : linear_ordered_semiring α], 2  0

Since the term fpow_sub two_ne_zero a b has no expected type (because it is in a rw), lean has to just elaborate it to find out what type it has. The a and b are no help to find the target type since they are always of type int in the lemma, so we just have a general variable α, which is apparently a linear_ordered_semiring and also a group_with_zero in order to make the applications make sense. But wait: we have an application here of one theorem to the other, and so 2 ≠ 0 in one theorem needs to match a ≠ 0 in the other, where the 0's are being provided by different typeclasses (recall that at this point we know only that α has two unrelated typeclasses, linear_ordered_semiring and group_with_zero, on it). At this point lean fails, because asking it to solve a commutative diagram in typeclass inference is too much. (It needs a type which has both typeclasses, such that the zero projections out of them are defeq.)

view this post on Zulip Bryan Gin-ge Chen (Apr 27 2020 at 01:58):

Thanks, that makes sense! It's surprising to me that rw can't find from the goal somehow.

view this post on Zulip Mario Carneiro (Apr 27 2020 at 01:58):

It first elaborates the term, then matches the target type against the subterms

view this post on Zulip Mario Carneiro (Apr 27 2020 at 01:58):

Otherwise it would have to re-elaborate the term many times

view this post on Zulip Kenny Lau (Apr 27 2020 at 05:02):

variables (α : Type) (x : α) (p : α  Prop)
example : ( x, p x)  ¬ ( x, ¬ p x) :=
⟨λ x, hx ha, ha x hx,
λ ha, classical.by_contradiction $ λ he, ha $ λ x hx, he x, hx⟩⟩

view this post on Zulip Kenny Lau (Apr 27 2020 at 05:03):

to write term mode proofs you just need to use a lot of underscores

view this post on Zulip Kenny Lau (Apr 27 2020 at 05:27):

and think backwards from the goal

view this post on Zulip Brandon Brown (Apr 27 2020 at 07:07):

I'm not familiar with the $ operator, and I don't see it used in TPIL

view this post on Zulip Kenny Lau (Apr 27 2020 at 07:09):

it just means open parenthesis

view this post on Zulip Kenny Lau (Apr 27 2020 at 07:09):

so it's the same as:

variables (α : Type) (x : α) (p : α  Prop)
example : ( x, p x)  ¬ ( x, ¬ p x) :=
⟨λ x, hx ha, ha x hx,
λ ha, classical.by_contradiction (λ he, ha (λ x hx, he x, hx))

view this post on Zulip Brandon Brown (Apr 27 2020 at 07:14):

ah it just saves a bunch of parentheses I see

view this post on Zulip AMM (Apr 27 2020 at 11:00):

Kevin Buzzard said:

@AMM I think https://artagnon.com/articles/leancoq does a good job of comparing Lean and Coq. In particular, I learnt from this article that Lean breaks "good type theoretic properties like strong normalization, subject reduction, and canonicity", and I have heard from Coq people that this is a big deal for some, but as a mathematician this breakage has never bothered me in the slightest. Another big difference is that "generic mathematicians" use Lean (people who do not specialise in type theory or higher categories or whatever -- they are just number theorists or analysts or geometers or topologists) -- and for me this is another of the main attractions.

Thank you very much!! This is really helpful. I also found your Newsletter of LMS article really useful when thinking about what the future looks like for interactive theorem proving!!

view this post on Zulip Dan Stanescu (Apr 27 2020 at 15:11):

I have a function defined like this: (X Y : set ℝ) (f : X → Y) and would like to use image_subset_range to get f(X) ⊆ Ybut not sure how to handle the set type casts that are involved. Can someone please help?

view this post on Zulip Kenny Lau (Apr 27 2020 at 15:15):

don't use partial functions

view this post on Zulip Chris Hughes (Apr 27 2020 at 15:16):

If f : X -> Y then f(X)f(X), will be written in Lean as set.range f. This is because when you write f : X -> Y, then X is being treated as a type rather than a set.

view this post on Zulip Chris Hughes (Apr 27 2020 at 15:16):

There's a coercion that turns sets into types

view this post on Zulip Chris Hughes (Apr 27 2020 at 15:17):

set.range f has type set Y, so it doesn't actually make sense in Lean straight away to say set.range f \subseteq Y since they have different types.

view this post on Zulip Dan Stanescu (Apr 27 2020 at 15:17):

So if I have my function like this I can't get that result? Because I saw that I could use f : \real \to \real instead.

view this post on Zulip Chris Hughes (Apr 27 2020 at 15:18):

It might be more sensible to use f : real -> real

view this post on Zulip Chris Hughes (Apr 27 2020 at 15:18):

And then I guess you'll need the assumption that f(X)Yf(X) \subseteq Y

view this post on Zulip Dan Stanescu (Apr 27 2020 at 15:22):

OK, thanks! Unfortunately that will make the result I'm eventually after quite a bit more difficult.

view this post on Zulip Kenny Lau (Apr 27 2020 at 15:22):

@Dan Stanescu do you have more context?

view this post on Zulip Patrick Massot (Apr 27 2020 at 15:24):

Dan Stanescu said:

OK, thanks! Unfortunately that will make the result I'm eventually after quite a bit more difficult.

This is a very natural belief, but almost surely wrong.

view this post on Zulip Dan Stanescu (Apr 27 2020 at 15:26):

@Kenny Lau The larger context is this:

import data.real.basic
import topology.basic
open function
open set

theorem countable_inj (X Y : set ) (f : X  Y) (hY : countable Y) :
    injective f  countable X :=
begin
   sorry,
end

view this post on Zulip Kenny Lau (Apr 27 2020 at 15:27):

it has nothing to do with R so might as well let X and Y be arbitrary types

view this post on Zulip Dan Stanescu (Apr 27 2020 at 15:27):

I agree. Never mind that.

view this post on Zulip Kenny Lau (Apr 27 2020 at 15:28):

also countable isn't defined

view this post on Zulip Dan Stanescu (Apr 27 2020 at 15:29):

I get it with my imports.

view this post on Zulip Patrick Massot (Apr 27 2020 at 15:29):

https://leanprover-community.github.io/mathlib_docs/data/set/countable.html

view this post on Zulip Chris Hughes (Apr 27 2020 at 15:31):

I never understood set.countable, set.finite, set.infinite etc. Shouldn't all of these things be about types?

view this post on Zulip Kenny Lau (Apr 27 2020 at 15:31):

import data.real.basic
import topology.basic
import data.set.countable
open function
open set

universes u v

theorem countable_inj (X Y : set ) (f : X  Y) (hY : countable Y) :
    injective f  countable X :=
λ hf, let g, hg := countable_iff_exists_injective.1 hY in
countable_iff_exists_injective.2 g  f, injective_comp hg hf

view this post on Zulip Patrick Massot (Apr 27 2020 at 15:31):

We need both, and the set version covers the type use through univ. But maybe we need more API around that.

view this post on Zulip Chris Hughes (Apr 27 2020 at 15:32):

But the type version covers sets by coercion.

view this post on Zulip Dan Stanescu (Apr 27 2020 at 15:33):

Kenny Lau said:

import data.real.basic
import topology.basic
import data.set.countable
open function
open set

universes u v

theorem countable_inj (X Y : set ) (f : X  Y) (hY : countable Y) :
    injective f  countable X :=
λ hf, let g, hg := countable_iff_exists_injective.1 hY in
countable_iff_exists_injective.2 g  f, injective_comp hg hf

Thanks Kenny! I think this will actually do.

view this post on Zulip Patrick Massot (Apr 27 2020 at 15:33):

Coercions can be nasty, so basing everything on them is dangerous

view this post on Zulip Frank Dai (Apr 27 2020 at 17:56):

Is there a way to have implicit arguments for \Sigma with the \< and \> syntax?

view this post on Zulip Kevin Buzzard (Apr 27 2020 at 17:56):

Just use _?

view this post on Zulip Sam Raleigh (Apr 28 2020 at 05:42):

universe u
variables {α : Type u} (K : finset α) {n : } [decidable_eq α]

def mono_sub_colorings (n : ) (k : ) : finset (finset (finset α)) := sorry

lemma num_mono_sub_colorings (n k : ) (h : n  k)
  := (card (mono_sub_colorings n k) : ) = (((2 : )^((n.choose(2)) - (k.choose(2))) : ) * n.choose(k)
begin
  sorry
end

Getting the following error:
"
type mismatch at application
2 ^ (choose n 2 - choose k 2) * ⇑(choose n k) ?m_1
term
⇑(choose n k) ?m_1
has type

but is expected to have type

"

Why is choose n k being coerced to \R? How can I fix this?

view this post on Zulip Sam Raleigh (Apr 28 2020 at 05:46):

What's even more bizarre to me is that if I remove the coercion from (card (mono_sub_colorings n k) : ℚ), then I get n.choose(k) is of type \Q.

view this post on Zulip Mario Carneiro (Apr 28 2020 at 06:12):

⇑(choose n k) ?m_1 this looks like choose is getting more arguments than it should

view this post on Zulip Mario Carneiro (Apr 28 2020 at 06:13):

You are missing a punctuation between the n.choose(k) and begin on the next line

view this post on Zulip Mario Carneiro (Apr 28 2020 at 06:13):

universe u
variables {α : Type u} (K : finset α) {n : } [decidable_eq α]

def mono_sub_colorings (n : ) (k : ) : finset (finset (finset α)) := sorry

lemma num_mono_sub_colorings (n k : ) (h : n  k)
  : (card (mono_sub_colorings n k) : ) = (((2 : )^((n.choose(2)) - (k.choose(2))) : ) * n.choose(k) :=
begin
  sorry
end

view this post on Zulip Mario Carneiro (Apr 28 2020 at 06:14):

It is a bit surprising that nat has a has_coe_to_fun involving real though

view this post on Zulip Mario Carneiro (Apr 28 2020 at 06:15):

what are your imports?

view this post on Zulip Scott Morrison (Apr 28 2020 at 07:37):

Bryan Gin-ge Chen said:

I guess it doesn't show up in by library_suggest by library_search because you need to convince Lean that 2 ≠ 0. It's the 3rd thing that comes up in by suggest.

Thanks to @Lucas Allen's recent PR improving library_search, you can now do things like:

import algebra.field_power

example (a b : ) : (2 : )^(a - b) = (2 : )^a / (2 : )^b :=
by library_search {discharger := `[exact dec_trivial]}

which works, reporting fpow_sub (of_as_true trivial) a b.

view this post on Zulip Scott Morrison (Apr 28 2020 at 07:41):

Another variant of library_search now available is

import algebra.field_power

example (a b : ) : (2 : )^(a - b) = (2 : )^a / (2 : )^b :=
by library_search [two_ne_zero]

view this post on Zulip Scott Morrison (Apr 28 2020 at 07:42):

which finds fpow_sub two_ne_zero a b.

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:05):

@Lucas Allen Thank you very very much!

view this post on Zulip Mario Carneiro (Apr 28 2020 at 08:23):

does by library_search {discharger := `[sorry]} work as expected?

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:24):

example : false := by library_search {discharger := `[sorry]}

should hopefully return exact sorry... I guess

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:25):

Indeed:

Try this: exact sorry

view this post on Zulip Mario Carneiro (Apr 28 2020 at 08:25):

no, the discharger should only be called on the subgoals of the theorem that was found

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:25):

So you want to find id sorry?

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:26):

Or absurd true sorry?

view this post on Zulip Mario Carneiro (Apr 28 2020 at 08:26):

I'm worried that this is what would happen

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:26):

Why are you worried?

view this post on Zulip Mario Carneiro (Apr 28 2020 at 08:26):

because that's a useless answer

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:27):

It sounds like you are looking for suggest, which works reasonably well.

view this post on Zulip Mario Carneiro (Apr 28 2020 at 08:27):

what I want is fpow_sub sorry a b.

view this post on Zulip Johan Commelin (Apr 28 2020 at 08:27):

That is probably what suggest would suggest

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:37):

fpow_sub _ a b is the fifth of so result for me from suggest.

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:37):

You're not going to do better than that with discharger := `[sorry].

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:38):

(i.e. in order to get fpow_sub sorry a b back from library_search, it's going to have to be the first result in suggest.)

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:39):

Actually, I think there must be a bug, because fpow_sub _ a b should come before everything that suggest puts ahead of it, on account of using more hypotheses.

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:39):

I'll look into it.

view this post on Zulip Kenny Lau (Apr 28 2020 at 08:42):

cf. the corresponding Coq tactic:

Require Import Arith.

Search (_ / _ = 0).

(*
Nat.div_small: forall a b : nat, a < b -> a / b = 0
Nat.div_0_l: forall a : nat, a <> 0 -> 0 / a = 0
Nat.div_1_l: forall a : nat, 1 < a -> 1 / a = 0
Nat.b2n_div2: forall a0 : bool, Nat.b2n a0 / 2 = 0
Nat.div_small_iff: forall a b : nat, b <> 0 -> a / b = 0 <-> a < b
*)

view this post on Zulip Mario Carneiro (Apr 28 2020 at 08:43):

I think suggest should also score matches based on how "deep" the match is, i.e. the number of constructor-equal-constructor unification subproblems. I'm not sure how best to phrase this in terms of the available information

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:43):

Oh, no, the problem is that I count "hypotheses used" just by checking if they appear in the partial result, and appearances in implicit arguments count too, so eq.symm _ gets counted as using a and b just as much as fpow_sub _ a b.

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:43):

Which is dumb...

view this post on Zulip Scott Morrison (Apr 28 2020 at 08:43):

there are some easy improvements to make, at least

view this post on Zulip Mario Carneiro (Apr 28 2020 at 08:44):

It's possible that simply weighting larger theorems as better (provided that they still have few remaining hypotheses) will do the trick

view this post on Zulip Reid Barton (Apr 28 2020 at 10:24):

Sam Raleigh said:

 := (card (mono_sub_colorings n k) : ) = (((2 : )^((n.choose(2)) - (k.choose(2))) : ) * n.choose(k)

There are so many parentheses here that it's hard to notice that the parentheses are not even balanced. You can simply write

(card (mono_sub_colorings n k) : ) = ((2 : )^(n.choose 2 - k.choose 2) : ) * n.choose k

All I did was remove parentheses and it's already much easier to read, but now you could notice that some of the : ℚs are redundant, as well.

view this post on Zulip Kenny Lau (Apr 28 2020 at 10:31):

(2 : ℚ) is redundant

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:36):

Is there any reason why by_library search would not work anymore? About halfway through my proof, Lean just doesn't seem to recognize the command anymore.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:40):

What is the first error in your file?

view this post on Zulip Reid Barton (Apr 28 2020 at 12:41):

Are you actually writing by_library search, or by library_search?

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:42):

It's at the very end, which is just "tactic failed, there are unsolved goals"

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:42):

And yeah, I misspelled, I was writing the latter @Reid Barton

view this post on Zulip Mario Carneiro (Apr 28 2020 at 12:42):

you should be writing the latter

view this post on Zulip Mario Carneiro (Apr 28 2020 at 12:43):

what error do you get when you write it?

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:46):

Unknown identifier "library_search"

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:46):

Are you in tactic mode? Can you just post code instead of making us play this guessing game?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:46):

Post fully working code so we can all see the error

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:48):

Okay, should I post the whole thing or a screenshot? How should I do it?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:49):

```
<paste code here>
```

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:49):

import analysis.normed_space.basic
import topology.instances.ennreal
import analysis.normed_space.basic
import topology.instances.ennreal
import algebra.archimedean algebra.geom_sum
import data.nat.choose data.complex.basic
import tactic.linarith
import analysis.calculus.deriv
import data.complex.exponential

open finset
open cau_seq
namespace complex
noncomputable theory


lemma is_cau_abs_cos (z : ) : is_cau_seq _root_.abs
  (λ n, (range n).sum (λ m, abs (
      ((-1) ^ m) * z ^ (2 * m ) / nat.fact (2 * m )))) :=
begin
sorry,
end

lemma is_cau_abs_sin (z : ) : is_cau_seq _root_.abs
  (λ n, (range n).sum (λ m, abs (
      ((-1) ^ m) * z ^ (2 * m + 1) / nat.fact (2 * m + 1)))) :=
begin
sorry,
/-
let ⟨n, hn⟩ := exists_nat_gt (abs z) in
have hn0 : (0 : ℝ) < n, from lt_of_le_of_lt (abs_nonneg _) hn,
series_ratio_test n (complex.abs z / n)
(div_nonneg_of_nonneg_of_pos (complex.abs_nonneg _) hn0)
  (by rwa [div_lt_iff hn0, one_mul])
  (λ m hm,
    by rw [abs_abs, abs_abs, nat.fact_succ, pow_succ,
      mul_comm m.succ, nat.cast_mul, ← div_div_eq_div_mul, mul_div_assoc,
      mul_div_right_comm, abs_mul, abs_div, abs_cast_nat];
    exact mul_le_mul_of_nonneg_right
      (div_le_div_of_le_left (abs_nonneg _) hn0
        (nat.cast_le.2 (le_trans hm (nat.le_succ _)))) (abs_nonneg _))
-/
end

lemma is_cau_sin (z : ) :
 is_cau_seq abs (λ n, (range n).sum (λ m,
 ((-1) ^ m) * z ^ (2 * m + 1) / nat.fact (2 * m + 1)))
:=
begin
    exact is_cau_series_of_abv_cau (is_cau_abs_sin z),
end

lemma is_cau_cos (z : ) :
 is_cau_seq abs (λ n, (range n).sum (λ m,
 ((-1) ^ m) * z ^ (2 * m ) / nat.fact (2 * m)))
:=
begin
    exact is_cau_series_of_abv_cau (is_cau_abs_cos z),
end

def sin' (z : ) : cau_seq  complex.abs :=
 ⟨λ n, (range n).sum
 (λ m, ((-1) ^ m) * z ^ (2 * m + 1) / nat.fact (2 * m + 1)),
 is_cau_sin z
def sin1 (z : ) :  := lim (sin' z)

def cos' (z : ) : cau_seq  complex.abs :=
 ⟨λ n, (range n).sum
 (λ m, (-1) ^ m * z ^ (2 * m) / nat.fact (2 * m)),
 is_cau_cos z
def cos1 (z : ) :  := lim (cos' z)

theorem euler :  x, exp (x * I) = cos1 x + sin1 x * I
:=
begin
    intros,

    have partials:  n: , (exp' (x*I)).1 (2*n+1) =
     (cos' x).1 (n+1) + ((sin' x).1 n) * I,
    {
        intros,
        rw exp',
        simp,
        rw cos',
        simp,
        rw sin',
        simp,

        induction n with n0 hn,
        { -- case n0=0
            simp,
        },
        { -- induction on n0
            rw sum_range_succ _ _, -- takes out last term in cos
            have lastSin :
            sum (range (nat.succ n0)) (λ (x_1 : ), (-1) ^ x_1 * x ^ (1 + 2 * x_1) / (nat.fact (1 + 2 * x_1)))
            =
            (-1) ^ n0 * x ^ (1 + 2 * n0) / (nat.fact (1 + 2 * n0))
            +
            sum (range (n0)) (λ (x_1 : ), (-1) ^ x_1 * x ^ (1 + 2 * x_1) / (nat.fact (1 + 2 * x_1)))
            ,
            {
              rw sum_range_succ _ _,
            },
            have sinFactorial :
            sum (range (nat.succ n0)) (λ (x_1 : ), (-1) ^ x_1 * x ^ (2 * x_1 + 1) / ((2 * x_1 + 1) * (nat.fact (2 * x_1))))
            =
            sum (range (nat.succ n0)) (λ (x_1 : ), (-1) ^ x_1 * x ^ (1 + 2 * x_1) / (nat.fact (1 + 2 * x_1))),
            {
              sorry,
              --lean should fucking know this!
            },
            rw sinFactorial,
            rw lastSin,

            have twoFromExp:
            sum (range (nat.succ (2 * nat.succ n0))) (λ (x_1 : ),
            (x * I) ^ x_1 / (nat.fact x_1))
            =
            (x * I) ^ ( 2 * nat.succ n0) / (nat.fact ( 2 * nat.succ n0))+
            sum (range ( 2 * nat.succ n0)) (λ (x_1 : ),
            (x * I) ^ x_1 / (nat.fact x_1))
            ,
            {
              rw sum_range_succ _ ( 2 * nat.succ n0),
            },
            have twoFromExpv1 :
            (x * I) ^ ( 2 * nat.succ n0) / (nat.fact ( 2 * nat.succ n0))+sum (range ( 2 * nat.succ n0)) (λ (x_1 : ), (x * I) ^ x_1 / (nat.fact x_1))
            =
            sum (range (nat.succ (2 * nat.succ n0))) (λ (x_1 : ),
            (x * I) ^ x_1 / (nat.fact x_1)),
             {
               by exact eq.symm twoFromExp,
             },

            have twoNP1 : 1+ (2 * nat.succ n0) =nat.succ (2 * nat.succ n0)
            ,
            {
              exact add_comm 1 (2 * nat.succ n0),
            },

            have twoNP1v1 : nat.succ ( 2 * nat.succ n0) = 1 + (2 * nat.succ n0),
            {
              by exact eq.symm twoNP1,
            },

            --rw twoNP1v1,
            rw twoFromExpv1,

            have oneFromExp:
            sum (range (2 * nat.succ n0)) (λ (x_1 : ), (x * I) ^ x_1 / (nat.fact x_1))
            =
            (x * I) ^ (1+2 * n0) / (nat.fact (1+2 * n0))
            +
            sum (range (1+ 2 * n0)) (λ (x_1 : ), (x * I) ^ x_1 / (nat.fact x_1))
            ,
            {
              have stupid : 2 * nat.succ n0 = nat.succ(1+2*n0),
              {
                have RRS : nat.succ(1+2*n0) = 1+(1+2*n0) ,
                {
                  sorry,
                },
                rw RRS,

                have realSt : 1+(1+2*n0) = 1+1+2*n0,
                {
                  simp,
                },
                rw realSt,
                exact nat.add_comm (nat.mul 2 n0) 2,
              },
              rw stupid,
              rw sum_range_succ _ (1 + 2 * n0),
            },
            --rw oneFromExp,
            --rw hn,
            --simp,

            --  need (x*I)^(2 n0 )= x^(2n0) (-1)^n0 etc, commutativity

            sorry,
            --ring,
        },
    },

    have partialExp : lim (exp' (x * I)) = exp (x*I),
    {
      sorry,
    },

    rw exp,
    rw partialExp,

    -- Now: need to take limits on both sides, they're same,
    -- but need to convince Lean that limit of exp' (2n+1) is same as
    -- limit of exp' (n) which is what exp is defined to be
end

end complex

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:51):

I get an error on line 96 but it's not about library_search

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:52):

How do I make the error Unknown identifier "library_search" appear on my screen?

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:53):

Funny, I sent this code to my professor and he got a different error on a different line, which I didn't see on my computer

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:53):

:-)

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:53):

I believe after line 88, Lean stops recognizing "by library_search"

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:54):

If people use different versions of Lean or mathlib they'll see different errors. Which version of Lean and mathlib are you using? [neither Lean nor mathlib are backwards compatible].

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 12:56):

For lean, it's 0.15.8

view this post on Zulip Patrick Massot (Apr 28 2020 at 12:56):

No, this is the VS code extension version.

view this post on Zulip Mario Carneiro (Apr 28 2020 at 12:56):

??

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:56):

You can click on terminal in the bottom window and type lean --version

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:57):

terminal.png

view this post on Zulip Reid Barton (Apr 28 2020 at 12:57):

Presumably if we know the mathlib version, we can work out the Lean version.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:58):

You can "pull up" on the blue bar at the bottom if you don't have this little window

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 12:58):

#print lean.version will also do it

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:01):

Hm, #print lean.version just gives this

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:01):

Capture.PNG

view this post on Zulip Johan Commelin (Apr 28 2020 at 13:02):

Seems like 3.7.2, which isn't too old.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:03):

Your code is taking a very long time to compile though. library_search might just be running out of memory.

view this post on Zulip Reid Barton (Apr 28 2020 at 13:03):

Hang on, isn't

euler.lean:88:8: error
invalid expression, unexpected token

an error which occurs earlier than the end of your file, and not "tactic failed, there are unsolved goals"?

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:04):

Right, that line compiles fine on my end, so I thought something was weird

view this post on Zulip Mario Carneiro (Apr 28 2020 at 13:04):

but you took the screenshot?

view this post on Zulip Reid Barton (Apr 28 2020 at 13:04):

I'm confused, aren't you showing screenshots of your own screen?

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:05):

Yes, I am

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:05):

Oh sorry, I see what yo mean now

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:05):

She's written #print in the tactic proof

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:05):

And how does Lean should know all those sum are finset sums? Did you open finset somewhere?

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:05):

Right, #print lean.version seems to give a compile error

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:05):

this works, but causes an error as well.

view this post on Zulip Reid Barton (Apr 28 2020 at 13:05):

Ohhh haha okay. I see.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:06):

Yeah, you can get rid of #print now.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:06):

Right -- in 3.9.0 the first problem is on line 96, with Lean not knowing about the sum

view this post on Zulip Reid Barton (Apr 28 2020 at 13:08):

open finset is on line 11 (if I counted correctly).

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:09):

@Patrick Massot what's the easiest way to get Lean 3.7.2 running with e.g. the last mathlib commit for 3.7.2?

view this post on Zulip Sam Raleigh (Apr 28 2020 at 13:10):

Mario Carneiro said:

what are your imports?

Thanks! my imports are:

import data.nat.basic
import data.int.basic
import data.rat.basic

import algebra.field_power

import tactic

import data.finset
import algebra.big_operators
import data.real.basic
import data.set.lattice

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:10):

I've made a new project, I can edit the toml to change 3.9.0 to 3.7.2 but now what?

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:10):

Ah, if I go into terminal I get this

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:10):

Capture.PNG

view this post on Zulip Johan Commelin (Apr 28 2020 at 13:11):

Hmm, that doesn't mean too much

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:11):

I'm not sure who to trust

view this post on Zulip Reid Barton (Apr 28 2020 at 13:11):

Right, so lean --version was actually not a useful question.

view this post on Zulip Johan Commelin (Apr 28 2020 at 13:11):

Because if you installed elan than the version of Lean depends on which directory you are in.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:11):

the terminal or the #print output

view this post on Zulip Reid Barton (Apr 28 2020 at 13:11):

All that matters is the mathlib version.

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:11):

Kevin, this use case is not supported by our tooling, you'll need to do it by hand (going to _target/deps/mathlib/ checkout the lean-3.7.2 branch, then leanproject get-matghlib-cache)

view this post on Zulip Reid Barton (Apr 28 2020 at 13:12):

(I mean assuming the user has elan installed and working correctly, but otherwise we'd have more obvious problems.)

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:12):

Are you working in a project @Stephanie Zhou ? Can you send the leanpkg.toml of the project?

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:12):

She ran this terminal thing from a random folder so it doesn't mean anything relevant

view this post on Zulip Mario Carneiro (Apr 28 2020 at 13:12):

@Sam Raleigh I'm still missing something. Do you have an MWE for the first example?

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:13):

But this whole discussion is a bit pointless. There is clearly a syntax error somewhere that confuses Lean. The problem will disappear simply by cleaning things up

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:13):

leanpkg.toml

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:13):

Mario, did you actually wanted to ping Sam here?

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:14):

If yes then we really need to get rid of this "noob question(s)" topic

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:15):

The whole stream is for noob questions, and putting all of them in the same topic is losing the organization by topic

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:15):

So Patrick I want to see if there's a syntax error with Stephanie's mathlib commit. If I change directory to _target/deps/mathlib and checkout the commit in her toml, I can just use leanproject get-mathlib-cache?

view this post on Zulip Mario Carneiro (Apr 28 2020 at 13:15):

I think that this topic is better than (no topic) for people who choose not to use topics, but we need a protocol for branching out a conversation to a real topic

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:15):

yes

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:16):

Yes there are two questions going on at once here

view this post on Zulip Sam Raleigh (Apr 28 2020 at 13:16):

I could shift my questions over to a different topic if that would help

view this post on Zulip Reid Barton (Apr 28 2020 at 13:16):

Now there are 3 :upside_down:

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:19):

OK so with Stephanie's mathlib commit, there are no errors before line 198

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:20):

Right, that's what I get too

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:21):

but library_search works for me on line 194, it returns failed because the result you want isn't in the library

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:22):

In general I would recommend not making such long proofs though, especially long proofs with the occasional sorry in. Lean gets slow in long proofs.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:24):

For example, your super-long proof on line 73 starts immediately with a have partials: ... . Why not make that its own lemma? Its proof is over 100 lines long which is still way too long.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:25):

--lean should fucking know this! rofl

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:25):

Our library still needs some work :-)

view this post on Zulip Reid Barton (Apr 28 2020 at 13:25):

We've all been there.

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:25):

Hm okay I see, Lean just doesn't return anything for by library_search, so I guess it timed out

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:26):

Oh, I might have default timeout set to higher

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:26):

I am an optimist

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:28):

Okay, how do I tinker with the default timeout setting?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:28):

            sum (range (nat.succ n0)) (λ (x_1 : ), (-1) ^ x_1 * x ^ (2 * x_1 + 1) / ((2 * x_1 + 1) * (nat.fact (2 * x_1))))
            =
            sum (range (nat.succ n0)) (λ (x_1 : ), (-1) ^ x_1 * x ^ (1 + 2 * x_1) / (nat.fact (1 + 2 * x_1))),

Lean shouldn't know this, it will follow from (1) commutativity of addition (2) nat.fact_succ (3) some statement about coercions commuting with equality. All three facts are known to Lean but it's too stupid to put everything together in the right order.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:28):

Or maybe it should know this -- but we haven't managed to put together a tactic which does everything obvious at once.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:29):

I agree that any maths student should know this!

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:31):

You can probably use congr' here to extract things from this mess.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:35):

It won't make library_search work :-) I went to File -> Preferences -> Settings and then searched for Lean Time Limit and changed the number to 900000. All that happens then is that library_search takes longer to fail. You should fix the cause of the problem though.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:36):

You are writing like a mathematician, with all this forward reasoning.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:37):

You make hypothesis after hypothesis, proving them all with relatively simple rewrites or sorry

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:37):

and then you rewrite each hypothesis to change your goal a bit.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:38):

It might be easier to use suffices a lot; that way your local context won't become clogged up with all these intermediate lemmas.

view this post on Zulip Kenny Lau (Apr 28 2020 at 13:39):

or prove more lemmas!

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 13:41):

Do you mean replace all the sorrys with suffices?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:42):

Stuff like this:

              have stupid : 2 * nat.succ n0 = nat.succ(1+2*n0),
              {
                have RRS : nat.succ(1+2*n0) = 1+(1+2*n0) ,
                {
                  sorry,
                },
                rw RRS,

                have realSt : 1+(1+2*n0) = 1+1+2*n0,
                {
                  simp,
                },
                rw realSt,
                exact nat.add_comm (nat.mul 2 n0) 2,
              },

just clogs up the local context. The ring tactic will solve all goals of this form, as long as you rw nat.succ_eq_add_one first to change the succs to +1's. But why make stupid a new hypothesis at all? The bigger you make your local context, the more difficult it is to see where you're going.

view this post on Zulip Steffan (Apr 28 2020 at 13:43):

But isn't sorry just a placeholder?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:43):

I mean that instead of

begin
  have A,
  { proof of A}
  rw A,
  have B,
  { proof of B},
  rw B,
  have C,
  ...

you could do other things (which won't leave A,B,C lying around as long hypotheses you'll never use again

view this post on Zulip Patrick Massot (Apr 28 2020 at 13:43):

Seeing all those nat.succ don't look good either. This function is really an implementation detail of natural numbers, it shouldn't show up outside of data.nat.basic

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:44):

They are there because it's a complicated induction proof.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:44):

After the induction tactic in one of the have goals, the goal is

 sum (range (2 * nat.succ n0 + 1)) (λ (m : ), (x * I) ^ m / (nat.fact m)) =
    sum (range (nat.succ n0 + 1)) (λ (m : ), (-1) ^ m * x ^ (2 * m) / (nat.fact (2 * m))) +
      sum (range (nat.succ n0))
          (λ (x_1 : ), (-1) ^ x_1 * x ^ (2 * x_1 + 1) / ((2 * x_1 + 1) * (nat.fact (2 * x_1)))) *
        I

view this post on Zulip Steffan (Apr 28 2020 at 13:45):

open nat, that's what I do

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:45):

that will get rid of the nat but not the succ

view this post on Zulip Steffan (Apr 28 2020 at 13:45):

I know
But it looks cleaner to me.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:45):

You could rw nat.succ_eq_add_one right now and you'll hopefully never see them again

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:49):

and then all of this lastSin -- you only make that proof so you can rewrite it, and you prove it with a rewrite, so you could just rewrite in your goal directly and never make lastSin at all.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 13:49):

Just work directly on the goal instead of making all these new hypotheses

view this post on Zulip Steffan (Apr 28 2020 at 13:53):

The ring tactic will solve all goals of this form

Turns out omega can solve that one too

view this post on Zulip Adeeb K (Apr 28 2020 at 15:12):

question - I have a proof p : f x = f y for an injective function f. What tactics would I use to conclude that x = y?
for reference, here's what I wrote for injectivity:

def injective {X Y} (f : X  Y) :=  x₁ x₂, f x₁ = f x₂  x₁ = x₂

view this post on Zulip Bryan Gin-ge Chen (Apr 28 2020 at 15:15):

injective f x y p is a proof of x = y.

view this post on Zulip Bryan Gin-ge Chen (Apr 28 2020 at 15:16):

(In your tactic proof, you would write exact injective f x y p)

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:17):

injective f is a function which eats two variables x₁ and x₂ and a proof that f x₁ = f x₂, and spits out a proof that x₁ = x₂

view this post on Zulip Brandon Brown (Apr 28 2020 at 15:18):

Can someone elucidate how the recursor is working for addition on the natural numbers?

-- nat.rec : ?M_1 0 → (Π (n : ℕ), ?M_1 n → ?M_1 (nat.succ n)) → Π (n : ℕ), ?M_1 n
def add (n m : nat) : nat :=
nat.rec_on n m (λ n z, nat.succ z)

view this post on Zulip Adeeb K (Apr 28 2020 at 15:19):

ah makes sense. so then I have p2 : f x = f y -> x = y and p : f x = f y. What would be the syntax to get the proposition that x = y?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:20):

#check @nat.rec_on
/-
nat.rec_on : Π {C : ℕ → Sort u_1} (n : ℕ), C 0 → (Π (n : ℕ), C n → C (nat.succ n)) → C n
-/

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:20):

p2 is also a function

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:20):

What do you think p2 takes as an input and what do you think it gives as an output?

view this post on Zulip Adeeb K (Apr 28 2020 at 15:20):

proof that f x = f y?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:21):

Right, that's the input

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:21):

Now f x = f y is a type in Lean's type theory, and p : f x = f y is a term of that type. Do you know what that means?

view this post on Zulip Adeeb K (Apr 28 2020 at 15:22):

Yes, at least I believe I do?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:22):

So what is p?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:22):

in normal language?

view this post on Zulip Adeeb K (Apr 28 2020 at 15:23):

p is a proposition of type f x = f y

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:23):

no, p is not a proposition.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:23):

f x = f y is a proposition.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:23):

p : f x = f y doesn't mean that p is equal to f x = f y

view this post on Zulip Bryan Gin-ge Chen (Apr 28 2020 at 15:24):

@Brandon Brown Are you already looking at the relevant section of Theorem Proving in Lean? If so, can you say more about what you'd like elucidated?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:24):

Lean needs to figure out the motive C, as you can see from the #check output with @ turned on.

view this post on Zulip Brandon Brown (Apr 28 2020 at 15:24):

Yes I am - I thought I understood everything up until that point in TPIL. Maybe I just need to stare at it longer

view this post on Zulip Adeeb K (Apr 28 2020 at 15:24):

is it more that p is of type f x = f y?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:25):

It knows that m : C 0

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:25):

so C 0 = ℕ

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:26):

and we know that (λ n z, nat.succ z) has type (Π (n : ℕ), C n → C (nat.succ n))

view this post on Zulip Adeeb K (Apr 28 2020 at 15:29):

oh, so now I have that x = y. Here, x and y are dependent pairs (x1, x2) and (y1, y2). How would I conclude that x1 = y1?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:30):

Well the problem is that you might not have names for x1 and y1 yet

view this post on Zulip Billy Price (Apr 28 2020 at 15:30):

@Adeeb K That's the exactly what using : in the statement p : f x = f y means. So now the question is "what is the data that inhabits the type f x = f y, which is a proposition" - i.e. what "is" p? In lean we don't actually have to define that, but it makes sense to call it a "proof" (of that proposition).

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:31):

so you might want to do cases x with x1 x2 and cases y with y1 y2 first

view this post on Zulip Brandon Brown (Apr 28 2020 at 15:31):

But it looks like the first argument going to nat.rec_on is n which corresponds to Π {C : ℕ → Sort u_1}, C 0

view this post on Zulip Adeeb K (Apr 28 2020 at 15:31):

thanks @Billy Price , that makes sense!
and @Kevin Buzzard I'll try that out now

view this post on Zulip Reid Barton (Apr 28 2020 at 15:31):

In fact, what you will want to do next depends on your exact goal

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:31):

and then the next step will depend on exactly what the type of x and y was. If they're subtypes then rw subtype.ext will do it, or perhaps ext

view this post on Zulip Billy Price (Apr 28 2020 at 15:32):

And if you think about, deciding that the inhabitants of a proposition are proofs, gives you the correspondence between implication A==>B and functions A -> B

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:32):

The squiggly brackets means "don't fill this in at all, Lean will fill it in for you"

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:32):

so n in add is the same as n in nat.rec_on

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:33):

and because nat.succ z has type , Lean can figure out that C (nat.succ _) = ℕ

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:34):

so Lean can figure out from the information given that C is the constant function sending every natural to

view this post on Zulip Brandon Brown (Apr 28 2020 at 15:34):

hmm ok, thanks - I need to chew on this a bit longer

view this post on Zulip Adeeb K (Apr 28 2020 at 15:35):

Okay I used cases to introduce x1 and x2, and I do have names for y1 and y2. How would I conclude that x1 = y1?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:35):

which is a roundabout way of saying that the function we're defining by induction is a function from the naturals to the naturals

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:35):

Adeeb K said:

Okay I used cases to introduce x1 and x2, and I do have names for y1 and y2. How would I conclude that x1 = y1?

That depends on the type of x

view this post on Zulip Adeeb K (Apr 28 2020 at 15:36):

it's a pair (k, k < m). So x1 is a natural

view this post on Zulip Reid Barton (Apr 28 2020 at 15:36):

Probably cc will do it, if you want a black-box answer.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:36):

So now we have to figure out what this function is. We can think of the function as a sequence of naturals. The first one is m, and then the inductive step (or rather the recursive step) sends z to succ(z), so the sequence is m, succ m, succ succ m, ...

view this post on Zulip Reid Barton (Apr 28 2020 at 15:36):

(Also, if you used cases on x and y, then presumably they were variables before and it would likely have been easier to subst the equality instead.)

view this post on Zulip Adeeb K (Apr 28 2020 at 15:37):

for context, I am trying to get x1 = y1 because I have a proof that x1 < y1, which is a contradiction

view this post on Zulip Reid Barton (Apr 28 2020 at 15:37):

How can you have x1, though?

view this post on Zulip Reid Barton (Apr 28 2020 at 15:37):

Do you mean you have a proof of x.1 < y.1?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:38):

so add n m is the n'th term in that sequence

view this post on Zulip Adeeb K (Apr 28 2020 at 15:39):

I have a proof that x.1 < y.1

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:40):

well if x just disappeared then you might have to dsimp that proof now

view this post on Zulip Reid Barton (Apr 28 2020 at 15:40):

Great, I am with you then. These might seem like terribly nitpicky questions but it's only because the correct tactics to use depend on details like this.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:40):

Adeeb K said:

it's a pair (k, k < m). So x1 is a natural

The question is not what the type of x1 is, it's what the type of x is.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:41):

Did you roll your own pair, or use fin m?

view this post on Zulip Adeeb K (Apr 28 2020 at 15:41):

so about a week ago I started a topic about pigeonhole, since I was writing it in lean for a seminar project. For the most part, it's done (the proof of pigeonhole itself is done), but I need to squash out some of the sorries from my helper functions

view this post on Zulip Adeeb K (Apr 28 2020 at 15:41):

I used my own pair

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:41):

did you prove the extensionality lemma for your pair?

view this post on Zulip Adeeb K (Apr 28 2020 at 15:41):

def finite_subset (n : ) := Σ' k, k < n

view this post on Zulip Adeeb K (Apr 28 2020 at 15:42):

not sure what that is exactly

view this post on Zulip Reid Barton (Apr 28 2020 at 15:42):

This isn't the direction for an extensionality lemma.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:42):

it's an ext_iff, right?

view this post on Zulip Reid Barton (Apr 28 2020 at 15:43):

You say you have p : x = y, and you want x.1 = y.1. There are several ways to do this, such as rewriting using p, or using congr_arg.

view this post on Zulip Adeeb K (Apr 28 2020 at 15:43):

so the outline of my plan is this:

view this post on Zulip Reid Barton (Apr 28 2020 at 15:44):

Another thing you could do is subst p, which will replace one of the variables (probably y) everywhere it occurs by x, leaving you with x.1 < x.1.

view this post on Zulip Adeeb K (Apr 28 2020 at 15:44):

eventually it came down to showing there is no injection from [m + 2] = {0, 1, ..., m + 1} to [m + 1], where I had an inductive hypothesis that there is no injection from [m + 1] to [m].

view this post on Zulip Reid Barton (Apr 28 2020 at 15:44):

Maybe it will replace x, I'm not sure.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:45):

lemma ext_iff (n : ) (a b : finite_subset n) : a = b  a.1 = b.1 :=
begin
  cases a,
  cases b,
  split,
  { intro h, rw h},
  { intro h, cases h, refl,}
end

view this post on Zulip Adeeb K (Apr 28 2020 at 15:46):

okay, I'll try those now!

view this post on Zulip Adeeb K (Apr 28 2020 at 15:48):

wait, I'm not sure how to use ext_iff in tactics
I tried let p4 := ext_iff p3 where p3 : x = y

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:48):

rw

view this post on Zulip Adeeb K (Apr 28 2020 at 15:48):

I'm sorry, it feels like I'm asking the same question over and over again..

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:49):

I think we're there now though

view this post on Zulip Adeeb K (Apr 28 2020 at 15:49):

rw failed I think?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:49):

rw ext_iff at p3

view this post on Zulip Adeeb K (Apr 28 2020 at 15:49):

I used rw ext_iff

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:49):

that rewrites the goal

view this post on Zulip Adeeb K (Apr 28 2020 at 15:49):

ah right my bad

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 15:50):

Alternatively have p4 := (ext_iff m x y).1 p3 will probably work

view this post on Zulip Adeeb K (Apr 28 2020 at 15:52):

so I have that x.1 and y.1 are the same. Here's the sketch of my proof:

view this post on Zulip Adeeb K (Apr 28 2020 at 15:54):

I wish to show that for an injective function f : [m + 2] -> [m + 1], the restriction of f to [m + 1]in the domain means that that there is no j in [m + 1] exists such that f (j, j < m + 2) = f (m + 1, m + 1 < m + 2)

view this post on Zulip Adeeb K (Apr 28 2020 at 15:56):

a human proof would go like the following: suppose not. Then we have by injectivity of f that (j, j < m + 2) = (m + 1, m + 1 < m + 2), which means j = m + 1, but we know that j < m + 1. Contradiction

view this post on Zulip Adeeb K (Apr 28 2020 at 15:57):

Here is the relevant code:

view this post on Zulip Adeeb K (Apr 28 2020 at 15:57):

def lift_one
(m : )
: finite_subset m  finite_subset (m + 1)
:= (lift_finite m (m+1) (succ_greater_than_nat m))

lemma miss_proof
(l : )
{m} (f : finite_subset (m + 2)  finite_subset (m + 1))
(inj : injective f)
{pf: m + 1 < m + 2}
:  j : finite_subset (m + 1), (f  lift_one (m + 1)) j  f m + 1,  pf
:= begin
introv p,
change f (lift_one (m+1) j) = f m + 1,  pf at p,
let p2 := inj (lift_one (m+1) j) m + 1,  pf,
let p3 := p2 p,
cases (lift_one (m + 1) j) with x1 x2,
rw ext_iff at p3,


end

view this post on Zulip Adeeb K (Apr 28 2020 at 15:58):

(I know I have to clean it up a bit)

view this post on Zulip Adeeb K (Apr 28 2020 at 15:59):

So the issue is that I have in the goal window that p3 : ⟨x1, x2⟩.fst = ⟨m + 1, pf⟩.fst, but how do I relate both sides to j and m + 1 respectively?

view this post on Zulip Reid Barton (Apr 28 2020 at 16:02):

So, Kevin gave you bad advice to use cases because you said you had a proof of x = y, suggesting x and y are variables, but actually you have a proof of lift_one (m + 1) j = ⟨m + 1, pf⟩.

view this post on Zulip Adeeb K (Apr 28 2020 at 16:03):

it was actually probably my bad for not sharing this in the first place, though

view this post on Zulip Adeeb K (Apr 28 2020 at 16:05):

either way, it doesn't seem linarith is seeing a contradiction after rw ext_iff at p3

view this post on Zulip Reid Barton (Apr 28 2020 at 16:06):

You should delete the cases line if you haven't already.

view this post on Zulip Adeeb K (Apr 28 2020 at 16:07):

yeah, that's done

view this post on Zulip Adeeb K (Apr 28 2020 at 16:07):

I now have p3 : (lift_one (m + 1) j).fst = ⟨m + 1, pf⟩.fst

view this post on Zulip Adeeb K (Apr 28 2020 at 16:10):

linarithisn't helping me here still

view this post on Zulip Reid Barton (Apr 28 2020 at 16:10):

Well, linarith doesn't know what to make of (lift_one (m + 1) j).fst of course.

view this post on Zulip Reid Barton (Apr 28 2020 at 16:12):

First you need to turn it into j.fst or whatever it should be.

view this post on Zulip Adeeb K (Apr 28 2020 at 16:13):

I see

view this post on Zulip Adeeb K (Apr 28 2020 at 16:13):

I'm not sure how to start with that

view this post on Zulip Reid Barton (Apr 28 2020 at 16:14):

Well, starting is the easy part:

lemma lift_one_fst ..... : (lift_one m j).fst = j.fst :=
...

view this post on Zulip Reid Barton (Apr 28 2020 at 16:14):

You haven't actually given us the definition of lift_one, I think.

view this post on Zulip Adeeb K (Apr 28 2020 at 16:15):

lemme do so

view this post on Zulip Adeeb K (Apr 28 2020 at 16:16):

lemma succ_greater_than_nat (n : ) : nat.succ n > n
:=
begin
  rw nat.succ_eq_add_one,
  linarith
end

/--
Type of pairs (k,p) where k
is a natural number and p is a witness to the proof that k < n.
-/
def finite_subset (n : ) := Σ' k, k < n

/--
Every pair that lives in finite_subest m lives in finite_subset n
where m < n
-/
def lift_finite (m n : ) (p : m < n) : finite_subset m  finite_subset n
    := λ k, k.1, lt.trans k.2 p

/--
Application of lift_finite from m to m + 1
-/
def lift_one
(m : )
: finite_subset m  finite_subset (m + 1)
:= (lift_finite m (m+1) (succ_greater_than_nat m))

view this post on Zulip Reid Barton (Apr 28 2020 at 16:19):

In that case, proving the lemma will be quite easy: it's true "by definition".

view this post on Zulip Adeeb K (Apr 28 2020 at 16:23):

oh? just refl?

view this post on Zulip Adeeb K (Apr 28 2020 at 16:24):

one moment

view this post on Zulip Adeeb K (Apr 28 2020 at 16:31):

okay, I have the lemma typed out

view this post on Zulip Adeeb K (Apr 28 2020 at 16:32):

lemma lift_one_fst {m} (j : finite_subset m) : (lift_one m j).fst = j.fst
:=
begin
refl,
end

view this post on Zulip Adeeb K (Apr 28 2020 at 16:32):

so now, I would:

rw (lift_one_fst j) p3

view this post on Zulip Adeeb K (Apr 28 2020 at 16:33):

or would I not?

view this post on Zulip Adeeb K (Apr 28 2020 at 16:36):

oh I got it

view this post on Zulip Adeeb K (Apr 28 2020 at 16:37):

let equal := lift_one_fst j,
rw equal at p3,

view this post on Zulip Adeeb K (Apr 28 2020 at 16:38):

okay cool, looks like this theorem is done with:

...
rw ext_iff at p3,
let equal := lift_one_fst j,
rw equal at p3,
let p4 := j.2,
linarith,

view this post on Zulip Reid Barton (Apr 28 2020 at 16:38):

You can just write rw lift_one_fst at p3. rw will figure out what arguments to insert for you.

view this post on Zulip Adeeb K (Apr 28 2020 at 16:41):

ah I see

view this post on Zulip Adeeb K (Apr 28 2020 at 16:41):

okay cool, that worked for this theorem! I'll likely be back with some more questions as I encounter problems in the main lemma

view this post on Zulip adriana (Apr 28 2020 at 17:13):

can anyone help me prove this lemma for the IVT? I'm very new and don't yet understand much.

def continuous2 (f:ℝ → ℝ ) :=
∀ x : ℝ, ∀ ε >0, ∃ δ > 0, ∀ y, abs (x-y) <δ → abs (f x - f y) < ε

lemma continuous_implies {f : ℝ → ℝ} (Hf : continuous2 f)
{a b : ℝ} (Hab : a < b) (K := {x : ℝ | x>a ∧ x<b ∧ f x < 0})
(c:= Sup K):
f c = 0
:=
by_contradiction

view this post on Zulip Patrick Massot (Apr 28 2020 at 17:19):

@adriana did you meant to post this twice? Using a dedicated topic was the right idea.

view this post on Zulip Adeeb K (Apr 28 2020 at 18:05):

hi small question

view this post on Zulip Adeeb K (Apr 28 2020 at 18:05):

suppose I have a variable named x_2 and just want to rename it y. How would I do so?

view this post on Zulip Reid Barton (Apr 28 2020 at 18:16):

I assume there is a rename tactic or something, but normally one would arrange for the variable to have the correct name in the first place; how did you get x_2?

view this post on Zulip Adeeb K (Apr 28 2020 at 18:17):

I used the intros tactic

view this post on Zulip Adeeb K (Apr 28 2020 at 18:18):

err

view this post on Zulip Adeeb K (Apr 28 2020 at 18:18):

the introv tactic

view this post on Zulip Adeeb K (Apr 28 2020 at 18:18):

but more than that, I have this:

view this post on Zulip orlando (Apr 28 2020 at 18:19):

intros y, ?

view this post on Zulip Adeeb K (Apr 28 2020 at 18:19):

let p := relabel (m + 1) k pf (f (lift_one (m + 1) x)) = relabel (m + 1) k pf (f (lift_one (m + 1) x₂)),
let x_l := (lift_one (m + 1) x),
let y_l := (lift_one (m + 1) x₂),

view this post on Zulip Adeeb K (Apr 28 2020 at 18:20):

How would I be able to then get the statement:

relabel (m + 1) k pf (f x_l) = relabel (m + 1) k pf (f y_l)

view this post on Zulip Adeeb K (Apr 28 2020 at 18:21):

I should add that I have p from my tactic state window

view this post on Zulip Reid Barton (Apr 28 2020 at 18:21):

p

view this post on Zulip Adeeb K (Apr 28 2020 at 18:21):

p?

view this post on Zulip Reid Barton (Apr 28 2020 at 18:22):

p already equals what you wrote

view this post on Zulip Reid Barton (Apr 28 2020 at 18:24):

if you have a proof of p and you really need a proof of relabel (m + 1) k pf (f x_l) = relabel (m + 1) k pf (f y_l) in particular then you can use change

view this post on Zulip Reid Barton (Apr 28 2020 at 18:24):

but most other tactics will not notice the difference anyways

view this post on Zulip Reid Barton (Apr 28 2020 at 18:25):

let is a tricky thing and it would be better to understand everything else first. But in general you can pretend something defined with let is the same as its definition.

view this post on Zulip Adeeb K (Apr 28 2020 at 18:25):

ah, I see.

view this post on Zulip Adeeb K (Apr 28 2020 at 18:27):

thanks!

view this post on Zulip Adeeb K (Apr 28 2020 at 18:28):

Okay, so new question:

view this post on Zulip Adeeb K (Apr 28 2020 at 18:29):

I have a definition for a function using if-then-else

view this post on Zulip Adeeb K (Apr 28 2020 at 18:29):

particularly:

view this post on Zulip Adeeb K (Apr 28 2020 at 18:29):

def relabel
(m k : )
(p: k < m)
: finite_subset m  finite_subset (m - 1)
:= λ j, if H : j.1  k then j.1, my_le_trans j.1 k m p H  else j.1 - 1, inequality_fact j.1 m j.2

view this post on Zulip Adeeb K (Apr 28 2020 at 18:31):

the function you helped me with earlier tells me that with an injective function f, there is no j in {0, 1, ..., m} such that f(j) = f(m + 1)

view this post on Zulip Adeeb K (Apr 28 2020 at 18:32):

With that, I want to show that the composition (relabel (m + 1) k pf) ∘ f ∘ lift_one (m + 1) is injective. I have already have that f is injective, and I have a lemma that any lifting is injective as well

view this post on Zulip Adeeb K (Apr 28 2020 at 18:32):

this is what I have so far:

view this post on Zulip Adeeb K (Apr 28 2020 at 18:32):

lemma relabel_inj
(m k : )
(p: k < m)
(f: finite_subset (m + 2)  finite_subset (m + 1))
(inj: injective f)
{pf} (miss:  j : finite_subset (m + 1), (f  lift_one (m + 1)) j  k,  pf )
: injective ((relabel (m + 1) k pf)  f  lift_one (m + 1))
:=
begin

  introv x,
  let y := x₂,
  intros,
  change (relabel (m + 1) k pf (f (lift_one (m + 1) x))) = (relabel (m + 1) k pf (f (lift_one (m + 1) x₂))) at a,
  let x_l := (lift_one (m + 1) x),
  let y_l := (lift_one (m + 1) x₂),
  change relabel (m + 1) k pf (f x_l) = relabel (m + 1) k pf (f y_l) at a,

  sorry,
end

view this post on Zulip Adeeb K (Apr 28 2020 at 18:33):

at this step, I want to be able to break this up into cases

view this post on Zulip Adeeb K (Apr 28 2020 at 18:34):

where relabel (f x_l) <= k and and when relabel (f x_l) > k

view this post on Zulip Adeeb K (Apr 28 2020 at 18:34):

and then apply my proof that f x_l != k to show we only have the cases for < and >

view this post on Zulip Adeeb K (Apr 28 2020 at 18:34):

does that make sense?

view this post on Zulip Adeeb K (Apr 28 2020 at 18:35):

would cases help me here in any way?

view this post on Zulip Adeeb K (Apr 28 2020 at 18:35):

or refine?

view this post on Zulip Adeeb K (Apr 28 2020 at 18:47):

Is this a better question as a new topic?

view this post on Zulip Bryan Gin-ge Chen (Apr 28 2020 at 18:50):

Yes, pretty much all questions that require > 1 reply would work better in their own topics.

view this post on Zulip Adeeb K (Apr 28 2020 at 18:50):

gotcha, gonna make it now.

view this post on Zulip Stephanie Zhou (Apr 28 2020 at 19:53):

I have version 3.7.2, but is it possible to downgrade to version 3.4.2? Will downloading v3.4.2 from github automatically overwrite the version I have?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 20:15):

Why would you want to downgrade? But you can -- it's not hard (I did it today when I created a 3.7.2 project to look at your code). It's just not documented :-)

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 20:15):

Do you know which commit of mathlib you want? As Reid said, this is the real question

view this post on Zulip Frank Dai (Apr 28 2020 at 22:22):

In my goal, I have a bunch of terms that look like this, after using simp

      {x := x, y := y, ar1 := q, ar2 := p}.ar1

Is there a way to get simp to unfold that to q?

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:30):

dsimp

view this post on Zulip Adeeb K (Apr 28 2020 at 22:46):

if I have x ≤ k and want to split into cases where x < k and x = k, how would I do so?

view this post on Zulip Alex J. Best (Apr 28 2020 at 22:48):

 cases lt_or_eq_of_le h,

if h is the name of your inequality.

view this post on Zulip Adeeb K (Apr 28 2020 at 22:49):

got it, thanks!

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:50):

import tactic

example (x k : ) : x  k  x < k  x = k := by library_search

is one way to answer questions like this yourself.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:52):

And another way is to learn the conventions for theorem naming. of means "is implied by", so you want to deduce something is less than, or equal to, given that it's lessthanorequalto, and the convention for less than is lt, and the convention for equals is eq, and the one for <= is le, so actually if you know these tricks then you can even guess the name of the theorem without using library_search.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:53):

It's not a perfect system -- for example it could have been eq_or_lt_of_le -- but it's a good start.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:53):

I guess after a while you've seen so many of them that you just start to learn them

view this post on Zulip Adeeb K (Apr 28 2020 at 22:53):

that makes sense. I've been going back and forth between the documentation, library search, and the natural number game.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:53):

Yeah, learning the names of all the 1000000 lemmas which you need to do anything at all is a tough part of the learning curve

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:54):

in nng I only work with one very basic type and build most things from scratch

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 22:54):

but you are working on a far harder problem so you need to know all sorts of things right from square 1, this is why it's so slow going

view this post on Zulip Adeeb K (Apr 28 2020 at 22:56):

yeah, it's definitely been an odyssey navigating through lean
that being said I've been having a lot of fun with this

view this post on Zulip Adeeb K (Apr 28 2020 at 22:57):

I underestimated how much work it would take to follow through even stating pigeonhole correctly - much less proving it all the way through

view this post on Zulip Bryan Gin-ge Chen (Apr 28 2020 at 22:57):

Feel free to suggest any improvements to docs here or on github!

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 23:00):

Do you think it would be ok to add a bunch of examples to the (say core) docs? There is an art here

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 23:01):

You don't want to say too much, but on the other hand I think that basic examples of usage of tactics would be helpful. In nng I tried to give an example of usage for every tactic I documented

view this post on Zulip Bryan Gin-ge Chen (Apr 28 2020 at 23:02):

I think that would be very helpful. More module docs that help "section" some of our giant files would be good too.

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 23:02):

I pointed Adeeb to the unfold docs earlier and then Reid pointed out that they were not ideal for a beginner

view this post on Zulip Kevin Buzzard (Apr 28 2020 at 23:03):

A couple of basic examples would have been very handy there

view this post on Zulip Adeeb K (Apr 28 2020 at 23:04):

I think 1 - 2 good "vertical slice" examples (ie, one example using a tactic in its simplest form and another similar to how I wanted to use unfold) would be really nice

view this post on Zulip Adeeb K (Apr 28 2020 at 23:15):

Question: I have equality between dependent pairs <x.fst, _> = <y.fst - 1, _> and an inequality k - 1 < y.fst - 1. How would I be able to rewrite the inequality as k - 1 < x.fst? The change tactic is saying a simple match fails.

view this post on Zulip Adeeb K (Apr 28 2020 at 23:18):

Would the extensionality theorem ext_iffwork here?

view this post on Zulip Adeeb K (Apr 28 2020 at 23:19):

update - it didn't work

view this post on Zulip Adeeb K (Apr 28 2020 at 23:20):

I used extensionality to say <x.fst, _>.fst = <y.fst - 1, _>.fst, but then change k - 1 < x.fst failed.

view this post on Zulip Reid Barton (Apr 28 2020 at 23:23):

change only works with things that are definitionally equal.

view this post on Zulip Adeeb K (Apr 28 2020 at 23:24):

ah, would there be another tactic for propositional equality?

view this post on Zulip Reid Barton (Apr 28 2020 at 23:26):

You already know how to rewrite things.

view this post on Zulip Adeeb K (Apr 28 2020 at 23:28):

I see

view this post on Zulip Adeeb K (Apr 28 2020 at 23:28):

that being said, I still got an error:

rewrite tactic failed, did not find instance of the pattern in the target expression
  x.fst, _⟩.fst

view this post on Zulip Adeeb K (Apr 28 2020 at 23:29):

This was when I used rw p2 at h4, where p2 : ⟨x.fst, _⟩.fst = ⟨y.fst - 1, _⟩.fst and h4 : k - 1 < y.fst - 1

view this post on Zulip Adeeb K (Apr 28 2020 at 23:38):

is there anything I'm missing? Any extra things I need to verify are equal?

view this post on Zulip Adeeb K (Apr 28 2020 at 23:39):

do I have to show that ⟨y.fst - 1, _⟩.fst = y.fst - 1?

view this post on Zulip Mario Carneiro (Apr 28 2020 at 23:40):

rfl

view this post on Zulip Reid Barton (Apr 28 2020 at 23:42):

You can change p2 into the required form for rw.

view this post on Zulip Adeeb K (Apr 28 2020 at 23:43):

okay, I'll try the latter suggestion first since that makes more immediate sense to me

view this post on Zulip Adeeb K (Apr 28 2020 at 23:43):

however, out of curiosity, how would I use rfl in this case @Mario Carneiro

view this post on Zulip Mario Carneiro (Apr 28 2020 at 23:44):

have: ⟨y.fst - 1, _⟩.fst = y.fst - 1 := rfl, more or less

view this post on Zulip Mario Carneiro (Apr 28 2020 at 23:44):

or rw show ⟨y.fst - 1, _⟩.fst = y.fst - 1, from rfl

view this post on Zulip Mario Carneiro (Apr 28 2020 at 23:46):

change is probably easier to use in your situation

view this post on Zulip Adeeb K (Apr 28 2020 at 23:54):

I see.

view this post on Zulip Adeeb K (Apr 28 2020 at 23:55):

So, I haveh : x.fst ≤ k and h_4 : nat.sub k 0 < x.fst but linearith is not giving me a contradiction.

view this post on Zulip Reid Barton (Apr 28 2020 at 23:57):

linarith does not know about this silly nat.sub. How did you even get it?

view this post on Zulip Frank Dai (Apr 28 2020 at 23:58):

How do you use the let tactic?

let a := begin /- long proof here -/ end,
-- how do you a term of the form a = <long expression>?

view this post on Zulip Reid Barton (Apr 28 2020 at 23:59):

on the other hand I suppose linarith does not know about - on nat either. Just get rid of it

view this post on Zulip Adeeb K (Apr 29 2020 at 00:00):

I used nat.le_of_pred_lt h4 (where h4 : k - 1 < x.fst) to get k ≤ x.fst

view this post on Zulip Adeeb K (Apr 29 2020 at 00:01):

except I didn't get k ≤ x.fst

view this post on Zulip Adeeb K (Apr 29 2020 at 00:01):

I got nat.sub k 0 ≤ x.fst

view this post on Zulip Reid Barton (Apr 29 2020 at 00:01):

Before you said nat.sub k 0 < x.fst

view this post on Zulip Reid Barton (Apr 29 2020 at 00:02):

@Frank Dai a is definitionally equal to <long expression>, so you can use rfl.

view this post on Zulip Adeeb K (Apr 29 2020 at 00:02):

oh yeah, this line is then after I split into cases where nat.sub k 0 < x.fst or nat.sub k 0 = x.fst

view this post on Zulip Frank Dai (Apr 29 2020 at 00:02):

I can do that but that requires me to copy the giant machine-generated expression that is a

view this post on Zulip Reid Barton (Apr 29 2020 at 00:03):

@Adeeb K I suggest moving your questions to a new topic.

view this post on Zulip Adeeb K (Apr 29 2020 at 00:04):

sure thing, thanks

view this post on Zulip Alex J. Best (Apr 29 2020 at 00:08):

@Frank Dai what do you need a term of the form a = long exp for?

view this post on Zulip Frank Dai (Apr 29 2020 at 00:09):

inside a proof, I am defining a function by a induction, and trying to prove something about that function

view this post on Zulip Frank Dai (Apr 29 2020 at 00:10):

I'm defining the function by

let f := begin <long induction proof> end,

and I want to prove later f x = f y or something.

view this post on Zulip Frank Dai (Apr 29 2020 at 00:11):

I don't know how to get the goal from f x = f y to <long expression> x = <long expression> y

view this post on Zulip Kenny Lau (Apr 29 2020 at 00:14):

my advice from experience is to never use the let tactic

view this post on Zulip Reid Barton (Apr 29 2020 at 00:14):

unfold f, or similar

view this post on Zulip Frank Dai (Apr 29 2020 at 00:14):

how do I make a local definition without let?

view this post on Zulip Frank Dai (Apr 29 2020 at 00:15):

I can't unfold f beacuse it's a local definition, not a global one

view this post on Zulip Kenny Lau (Apr 29 2020 at 00:15):

don't make local definitions

view this post on Zulip Reid Barton (Apr 29 2020 at 00:15):

Try anyways?

view this post on Zulip Reid Barton (Apr 29 2020 at 00:15):

Local definitions are fine, but you should definitely think twice about whether you want to make a big one

view this post on Zulip Alex J. Best (Apr 29 2020 at 00:17):

I'm a little confused you are using let for a proof? Use have if it is a term of type Prop.
That said

example : false :=
begin
let f := λ n, n+2,
suffices : f 1 = f 2, sorry, -- this is irrelevant I just wanted a goal like you have
dsimp [f],
end

view this post on Zulip Frank Dai (Apr 29 2020 at 00:18):

that works if the goal is trivial, the problem is that I don't know how to easily rewrite f into \lam n, n + 2

view this post on Zulip Frank Dai (Apr 29 2020 at 00:18):

which you need to do for a non-trivial proof

view this post on Zulip Kenny Lau (Apr 29 2020 at 00:18):

the answer is dsimp only [f]

view this post on Zulip Kenny Lau (Apr 29 2020 at 00:19):

but my answer is make it a global definition

view this post on Zulip Frank Dai (Apr 29 2020 at 00:21):

more trivial question: how do you apply a tactic to all goals simultaneously

view this post on Zulip Alex J. Best (Apr 29 2020 at 00:21):

all_goals { tactic }

view this post on Zulip Kenny Lau (Apr 29 2020 at 00:22):

if the goals are produced by a single tactic then you can use ; instead of ,

view this post on Zulip Mario Carneiro (Apr 29 2020 at 00:23):

You should not use tactics to define functions if you can help it

view this post on Zulip Mario Carneiro (Apr 29 2020 at 00:23):

your inductive definition should be a separate auxiliary

view this post on Zulip Frank Dai (Apr 29 2020 at 00:24):

is the reason for this that there's more magic for global definitions?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 00:27):

basically

view this post on Zulip Mario Carneiro (Apr 29 2020 at 00:28):

Most of the time when you do this local definition thing lean is making an auxiliary anyway

view this post on Zulip Mario Carneiro (Apr 29 2020 at 00:28):

when you write a recursive definition with the equation compiler, you get nice equations that don't require you to look at giant machine generated definitions

view this post on Zulip Frank Dai (Apr 29 2020 at 00:32):

after reaching a 250 line-long goal buffer, I see your point

view this post on Zulip Mario Carneiro (Apr 29 2020 at 00:34):

and it's more than visual overload; that term is much harder to work with using the normal tactics

view this post on Zulip Stephanie Zhou (Apr 29 2020 at 00:44):

@Kevin Buzzard how did you downgrade lean this morning?

view this post on Zulip Billy Price (Apr 29 2020 at 00:48):

I want a collection data type where I can define a function out of it which folds it into a proposition based on the index of each element in the collection. Which collection should I use and where should I look for examples of how to use it?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 01:04):

maybe \forall i, a i?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 01:06):

If you are thinking about the context data type for your type theory project, I would suggest sticking to lists

view this post on Zulip Mario Carneiro (Apr 29 2020 at 01:06):

there are ways to talk about the nth item of a list

view this post on Zulip Frank Dai (Apr 29 2020 at 01:44):

When do you use simp vs dsimp in general? They seem to have subtly different behavior. Are there general heuristics on when to use which one?

view this post on Zulip Kenny Lau (Apr 29 2020 at 01:46):

dsimp only simplifies using definitional equalities (lemmas proved by rfl)

view this post on Zulip Kenny Lau (Apr 29 2020 at 01:47):

(but my answer is to avoid them and always append only if you have to use them)

view this post on Zulip Frank Dai (Apr 29 2020 at 01:51):

What are the alternatives?

view this post on Zulip Kenny Lau (Apr 29 2020 at 01:52):

rw

view this post on Zulip Frank Dai (Apr 29 2020 at 01:56):

like for instance I have (lam x, <something>) xI want to rewrite to <something>

view this post on Zulip Kenny Lau (Apr 29 2020 at 01:57):

dsimp only,

view this post on Zulip Adeeb K (Apr 29 2020 at 02:33):

Question - if I have a function defined with the if-then-else pattern, and I have a proof that an input falls into the if case, how can I then conclude that I have an exact form for my function?

view this post on Zulip Adeeb K (Apr 29 2020 at 02:35):

that is, suppose I have the function

def function (z : N) : N := if z < 5 then z else z + 1

Now suppose I have

p : z < 5

How can I conclude that f z = z?

view this post on Zulip Reid Barton (Apr 29 2020 at 02:36):

simp [function] would be the easiest way

view this post on Zulip Adeeb K (Apr 29 2020 at 02:37):

So in the above, I would say

let g := f z

and then
simp g
?

view this post on Zulip Adeeb K (Apr 29 2020 at 02:37):

that gave me an error

view this post on Zulip Adeeb K (Apr 29 2020 at 02:39):

I'm not sure how to use simp here then

view this post on Zulip Kenny Lau (Apr 29 2020 at 02:45):

rw [function, if_pos p]

view this post on Zulip Reid Barton (Apr 29 2020 at 02:46):

Right, you need to include p too of course.

view this post on Zulip Adeeb K (Apr 29 2020 at 02:48):

would function here be g or f?

view this post on Zulip Kenny Lau (Apr 29 2020 at 02:48):

you shouldn't use let

view this post on Zulip Kenny Lau (Apr 29 2020 at 02:48):

]

view this post on Zulip Adeeb K (Apr 29 2020 at 02:48):

what should I use?

view this post on Zulip Kenny Lau (Apr 29 2020 at 02:50):

have : function z = z, rw [function, if_pos p]

view this post on Zulip Adeeb K (Apr 29 2020 at 02:52):

It's not working

view this post on Zulip Kenny Lau (Apr 29 2020 at 02:53):

MWE

view this post on Zulip Adeeb K (Apr 29 2020 at 02:53):

should I send you a MWE?

view this post on Zulip Adeeb K (Apr 29 2020 at 02:57):

import tactic


lemma succ_greater_than_nat (n : ) : nat.succ n > n
:=
begin
  rw nat.succ_eq_add_one,
  linarith
end

def injective {X Y} (f : X  Y) :=  x₁ x₂, f x₁ = f x₂  x₁ = x₂

def finite_subset (n : ) := { k // k < n }

def lift_finite (m n : ) (p : m < n) : finite_subset m  finite_subset n
    := λ k, k.1, lt.trans k.2 p


lemma ext_iff (n : ) (a b : finite_subset n) : a = b  a.1 = b.1 :=
begin
  cases a,
  cases b,
  split,
  { intro h, rw h},
  { intro h, cases h, refl,}
end

def lift_one
(m : )
: finite_subset m  finite_subset (m + 1)
:= (lift_finite m (m+1) (succ_greater_than_nat m))


lemma lift_one_fst {m} (j : finite_subset m) : (lift_one m j).1 = j.1
:= begin refl, end


def relabel (m k : ) (h : k < m) (j : finite_subset m) : finite_subset (m - 1) :=
if H : j.1  k then j.1, sorry else j.1 - 1, sorry

lemma miss_proof
{m} (f : finite_subset (m + 2)  finite_subset (m + 1))
(inj : injective f)
{pf: m + 1 < m + 2}
:  j : finite_subset (m + 1), (f  lift_one (m + 1)) j  f m + 1,  pf
:= begin

introv p,
change f (lift_one (m+1) j) = f m + 1,  pf at p,
let p2 := inj (lift_one (m+1) j) m + 1,  pf,
let p3 := p2 p,
rw ext_iff at p3,
rw lift_one_fst at p3,
let p4 := j.2,
linarith,

end

lemma relabel_behavior (m k : ) (h : k < m) (x y : finite_subset m) (hxy : relabel m k h x = relabel m k h y) :
  (x.1  k  y.1  k)  (x.1  k  y.1  k) :=
begin
  unfold relabel at hxy,
  split_ifs at hxy with hxk hyk hyk,
  { left; split; assumption },
  { right; split,


    { rw subtype.mk_eq_mk at hxy,


      cases lt_or_eq_of_le hxk with hxlk hxek,
      { rw hxy at hxlk, exact absurd (nat.le_of_pred_lt hxlk) hyk },
      { exact ge_of_eq hxek } },
    { exact le_of_not_ge hyk } },
  { right; split,
    { exact le_of_not_ge hxk },
    { rw subtype.mk_eq_mk at hxy,
      cases lt_or_eq_of_le hyk with hylk hyek,
      { rw  hxy at hylk, exact absurd (nat.le_of_pred_lt hylk) hxk },
      { exact ge_of_eq hyek } } },
  { right; split; apply le_of_not_ge; assumption }


end


lemma relabel_inj
(m k : )
(p: k < m)
(f: finite_subset (m + 2)  finite_subset (m + 1))
(inj: injective f)
{pf} (miss:  j : finite_subset (m + 1), (f  lift_one (m + 1)) j  k,  pf )
: injective ((relabel (m + 1) k pf)  f  lift_one (m + 1))
:=
begin



  introv x,
  let y := x₂,
  intros,

  let miss_x := miss x,
  let miss_y := miss y,

  change (relabel (m + 1) k pf (f (lift_one (m + 1) x))) = (relabel (m + 1) k pf (f (lift_one (m + 1) x₂))) at a,
  let x_l := (lift_one (m + 1) x),
  let y_l := (lift_one (m + 1) x₂),
  change relabel (m + 1) k pf (f x_l) = relabel (m + 1) k pf (f y_l) at a,

  let r_x_l := relabel (m + 1) k pf (f x_l),

  let r_y_l := relabel (m + 1) k pf (f y_l),



  --split_ifs at a,
  --change r_x_l = r_y_l at a,

  sorry,
end

view this post on Zulip Adeeb K (Apr 29 2020 at 02:58):

The issue I'm having is towards the bottom of relabel_inj after the last change

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:09):

what's the point of let miss_x := miss x,?

view this post on Zulip Adeeb K (Apr 29 2020 at 03:10):

that will let me conclude that x.1 < k or x.1 > k

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:11):

I don't see the point of any of your lets

view this post on Zulip Adeeb K (Apr 29 2020 at 03:12):

I started writing let's to make the statement simpler, but then the others here suggested I write lemmas to help out.

view this post on Zulip Adeeb K (Apr 29 2020 at 03:12):

relabel_behavior being one and miss_proof being another

view this post on Zulip Reid Barton (Apr 29 2020 at 03:12):

You should write a better lemma maybe.

view this post on Zulip Adeeb K (Apr 29 2020 at 03:12):

(miss is supposed to be a consequence of miss_proof)

view this post on Zulip Adeeb K (Apr 29 2020 at 03:13):

as in a better lemma than relabel_inj?

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:13):

your lemma is fine

view this post on Zulip Reid Barton (Apr 29 2020 at 03:13):

No, I assume you already have a purpose for relabel_inj.

view this post on Zulip Reid Barton (Apr 29 2020 at 03:13):

I mean a lemma that you can use to prove relabel_inj

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:13):

but my suggestion didn't work because it's supposed to be dif_pos

view this post on Zulip Adeeb K (Apr 29 2020 at 03:14):

I'm not exactly sure what that means or where to go from there

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:15):

lemma relabel_inj (m k : ) (hkm : k < m) (f: finite_subset (m + 2)  finite_subset (m + 1)) (inj : injective f)
  {pf} (miss :  j : finite_subset (m + 1), (f  lift_one (m + 1)) j  k, pf ) :
  injective ((relabel (m + 1) k pf)  f  lift_one (m + 1)) :=
begin
  intros x y h,
  change (relabel (m + 1) k pf (f (lift_one (m + 1) x))) = (relabel (m + 1) k pf (f (lift_one (m + 1) y))) at h,
  rcases relabel_behavior _ _ _ _ _ h with h1, h2 | h1, h2⟩; unfold relabel at h,
  { rw [dif_pos h1, dif_pos h2, subtype.mk_eq_mk] at h, }
end

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:15):

start with this

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:16):

learn to work with long expressions

view this post on Zulip Adeeb K (Apr 29 2020 at 03:17):

okay, give me a second

view this post on Zulip Adeeb K (Apr 29 2020 at 03:17):

thanks again

view this post on Zulip Adeeb K (Apr 29 2020 at 03:19):

I'm getting an error within the parentheses on the bottom

solve1 tactic failed, focused goal has not been solved

view this post on Zulip Reid Barton (Apr 29 2020 at 03:20):

I think that is because the goal has not been solved.

view this post on Zulip Adeeb K (Apr 29 2020 at 03:20):

oh..I need to fill in the stuff there. right right, my bad

view this post on Zulip Adeeb K (Apr 29 2020 at 03:21):

wait question about this

view this post on Zulip Adeeb K (Apr 29 2020 at 03:21):

This gives me

h1 : (f (lift_one (m + 1) x)).val  k,
h2 : (f (lift_one (m + 1) y)).val  k,

view this post on Zulip Jalex Stark (Apr 29 2020 at 03:23):

Adeeb K said:

wait question about this

what's the question?

view this post on Zulip Adeeb K (Apr 29 2020 at 03:24):

how would I conclude that

(relabel m k p (f (lift_one (m + 1) x))) =   (f (lift_one (m + 1) x)).val,  pf : (f (lift_one (m + 1) x)).val < m ,

view this post on Zulip Reid Barton (Apr 29 2020 at 03:24):

Adeeb likes to warn us when a question is coming, so we are not too surprised.

view this post on Zulip Reid Barton (Apr 29 2020 at 03:25):

Weren't you planning to write a lemma for this?

view this post on Zulip Adeeb K (Apr 29 2020 at 03:26):

I was, but then Kenny mentioned it was only a single line, but he seemed to use what he told me to give me another code snippet?

view this post on Zulip Reid Barton (Apr 29 2020 at 03:26):

Everything is a single line to Kenny

view this post on Zulip Jalex Stark (Apr 29 2020 at 03:27):

just because something is a single line doesn't mean it's a bad lemma

view this post on Zulip Reid Barton (Apr 29 2020 at 03:27):

anyways, you need to use dif_pos

view this post on Zulip Jalex Stark (Apr 29 2020 at 03:27):

there are a lot of lemmas in mathlib whose proof is just rfl

view this post on Zulip Adeeb K (Apr 29 2020 at 03:27):

alright, I'll give it a shot. I'll post the statement in a second

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:27):

there are a lot of lemmas that are one line, possibly the majority

view this post on Zulip Jalex Stark (Apr 29 2020 at 03:29):

but if you think like a mathematician a lot of those one-liners are longer than one line

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:29):

yeah, they correspond to mathematician proofs of about 1 - 5 lines

view this post on Zulip Steffan (Apr 29 2020 at 03:30):

some easy ones are just by ring/by omega or something in Lean

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:30):

of course many of them have the one line proof "Trivial."

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:31):

I think it's pretty rare to see lemmas that are literally by heavy_tactic

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:31):

except possibly all the by obviously proofs in category theory

view this post on Zulip Adeeb K (Apr 29 2020 at 03:31):

okay, here we are:

lemma apply_relabel_gt
(m k : )
(p : k < m)
(z : finite_subset m)
(p2 : z.1  k)
(p3 : z.1 < m - 1)
: (relabel m k p) z =  z.1, p3 
:=
begin
sorry,
end

view this post on Zulip Adeeb K (Apr 29 2020 at 03:32):

Actually I'll make this an MWE

view this post on Zulip Adeeb K (Apr 29 2020 at 03:33):

import tactic


def finite_subset (n : ) := { k // k < n }

def relabel (m k : ) (h : k < m) (j : finite_subset m) : finite_subset (m - 1) :=
if H : j.1  k then j.1, sorry else j.1 - 1, sorry


lemma apply_relabel_gt
(m k : )
(p : k < m)
(z : finite_subset m)
(p2 : z.1  k)
(p3 : z.1 < m - 1)
: (relabel m k p) z =  z.1, p3 
:=
begin
    sorry,
end

view this post on Zulip Adeeb K (Apr 29 2020 at 03:33):

I'm not sure how to proceed with dif_pos.

view this post on Zulip Steffan (Apr 29 2020 at 03:35):

I think it's pretty rare to see lemmas that are literally by heavy_tactic

yeah, it seems kind of crazy to do this heavy ring to prove n + 1 + 1 = n + 2

but I don't terribly care about performance in theorem proving

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:36):

It starts to matter when you have a big library with many dependent files like mathlib

view this post on Zulip Steffan (Apr 29 2020 at 03:36):

yeah, but that != me atm :D

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:37):

but it's not (just) about performance; it's often the case that the reason this is a lemma is because it isn't easily killed by one tactic

view this post on Zulip Reid Barton (Apr 29 2020 at 03:37):

Or it is used by the implementation of the tactic that would kill it.

view this post on Zulip Adeeb K (Apr 29 2020 at 03:37):

I'm also not seeing any entry for dif_pos in the mathlib tactics documentation?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:37):

it might be by induction n; heavy_tactic or by simpa using nonobvious term

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:38):

import tactic

def finite_subset (n : ) := { k // k < n }

def relabel (m k : ) (h : k < m) (j : finite_subset m) : finite_subset (m - 1) :=
if H : j.1  k then j.1, sorry else j.1 - 1, sorry

lemma apply_relabel_gt (m k : ) (hkm : k < m) (z : finite_subset m) (h2 : z.1  k) (h3 : z.1 < m - 1) :
  relabel m k hkm z = z.1, h3 :=
begin
  unfold relabel, rw dif_pos h2
end

view this post on Zulip Reid Barton (Apr 29 2020 at 03:38):

by nonobviously :upside_down:

view this post on Zulip Steffan (Apr 29 2020 at 03:38):

you're right, it's kinda pointless to prove trivial stuff anyway

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:38):

but rfl is also a common way to prove nontrivial theorems trivially

view this post on Zulip Adeeb K (Apr 29 2020 at 03:38):

oh. thanks again Kenny

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:40):

@Adeeb K You don't often have to refer to dif_pos since simp knows about it

view this post on Zulip Adeeb K (Apr 29 2020 at 03:40):

oh wait, so when I try and do the other case

view this post on Zulip Adeeb K (Apr 29 2020 at 03:40):

I get an error

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:40):

unless you are avoiding simp like kenny

view this post on Zulip Steffan (Apr 29 2020 at 03:40):

like literally, rfl will solve 6 * finset.sum (range (0 + 1)) (λ (n : ℕ), n ^ 2) = 0 * (0 + 1) * (2 * 0 + 1)

view this post on Zulip Adeeb K (Apr 29 2020 at 03:41):

@Kenny Lau I tried using what you wrote for the case when z > k. Here it is:

import tactic

def finite_subset (n : ) := { k // k < n }

def relabel (m k : ) (h : k < m) (j : finite_subset m) : finite_subset (m - 1) :=
if H : j.1  k then j.1, sorry else j.1 - 1, sorry

lemma apply_relabel_gt (m k : ) (hkm : k < m) (z : finite_subset m) (h2 : z.1 > k) (h3 : z.1 < m - 1) :
  relabel m k hkm z = z.1, h3 :=
begin
  unfold relabel,
  rw dif_pos h2,
end

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:41):

The asymptotic complexity of checking that a proof by rfl is correct is gargantuan

view this post on Zulip Adeeb K (Apr 29 2020 at 03:42):

I'm getting an error on the last line rw dif_pos h2

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:42):

import tactic

def finite_subset (n : ) := { k // k < n }

def relabel (m k : ) (h : k < m) (j : finite_subset m) : finite_subset (m - 1) :=
if H : j.1  k then j.1, sorry else j.1 - 1, sorry

lemma apply_relabel_gt (m k : ) (hkm : k < m) (z : finite_subset m) (h2 : k < z.1) (h3 : z.1 < m - 1) :
  relabel m k hkm z = z.1, h3 :=
begin
  unfold relabel,
  rw dif_neg (not_le_of_lt h2),
end

view this post on Zulip Reid Barton (Apr 29 2020 at 03:43):

Adeeb, you should read the error and look at the type of dif_pos.

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:43):

dif_pos says that a dependent if-then-else expression is equal to the then case when the condition is true

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:43):

if the condition is false of course you shouldn't try to prove it is true

view this post on Zulip Adeeb K (Apr 29 2020 at 03:43):

this gives me

m k : ,
hkm : k < m,
z : finite_subset m,
h2 : k < z.val,
h3 : z.val < m - 1
 z.val - 1, _⟩ = z.val, h3

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:44):

if you see a false conclusion it's time to review your statement

view this post on Zulip Steffan (Apr 29 2020 at 03:45):

relabel has sorry in it

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:45):

that doesn't matter

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:45):

actually it won't matter because of proof irrelevance

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:45):

but you should probably fix that sorry

view this post on Zulip Steffan (Apr 29 2020 at 03:46):

vscode is bugging me about it

view this post on Zulip Adeeb K (Apr 29 2020 at 03:47):

oh shoot right, I forgot to use a -1 when modifying

view this post on Zulip Adeeb K (Apr 29 2020 at 03:48):

so this is correct:

lemma apply_relabel_gt (m k : )
(hkm : k < m)
(z : finite_subset m)
(h2 : k < z.1)
(h3 : z.1 - 1 < m - 1)
: relabel m k hkm z = z.1 - 1, h3
:= begin
  unfold relabel,
  rw dif_neg (not_le_of_lt h2),
end

view this post on Zulip Kenny Lau (Apr 29 2020 at 03:50):

if VSCode doesn't complain about it then it's correct

view this post on Zulip Steffan (Apr 29 2020 at 03:53):

but I mean... it looks like you're proving that sorry = h3.

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:54):

this is true because sorry is a proof of z.1 - 1 < m - 1 and so is h3 so they are defeq by proof irrelevance

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:54):

because z.1 - 1 < m - 1 : Prop

view this post on Zulip Adeeb K (Apr 29 2020 at 03:55):

@Kenny Lau you said that I shouldn't use let. Then if I have h1 : (f (lift_one (m + 1) x)).val ≤ k, how would I extract a statement that relabel m k hkm (f (lift_one (m + 1) x)) = ⟨ (f (lift_one (m + 1) x).val , (f (lift_one (m + 1) x) < m ⟩ using apply_relabel_gt?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:56):

what is f? Is it a let?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:56):

If you don't use let then it just has the full expression in there already

view this post on Zulip Reid Barton (Apr 29 2020 at 03:57):

f is an argument to the theorem

view this post on Zulip Reid Barton (Apr 29 2020 at 03:57):

a variable

view this post on Zulip Adeeb K (Apr 29 2020 at 03:57):

f : finite_subset (m + 2) → finite_subset (m + 1) is given as an argument

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:57):

in that case I don't understand the question, what does let have to do with anything

view this post on Zulip Reid Barton (Apr 29 2020 at 03:58):

Anyways you just apply apply_relabel_gt to the right things. Have you done the natural number game?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 03:58):

relabel is a def and it has theorems about it, and you use those theorems and that's all there is to it

view this post on Zulip Adeeb K (Apr 29 2020 at 03:58):

I mean, I have h : (f (lift_one (m + 1) x)).val = (f (lift_one (m + 1) y)).val

view this post on Zulip Reid Barton (Apr 29 2020 at 03:59):

I think Adeeb means: instead of naming f (lift_one (m+1) x) or something with a let. How to do it without any let.

view this post on Zulip Reid Barton (Apr 29 2020 at 03:59):

Not that the let would help of course.

view this post on Zulip Steffan (Apr 29 2020 at 04:00):

sorry was a macro for a placeholder, I thought? and Lean threw errors about it? I guess I don't even know what sorry is. ;)

view this post on Zulip Mario Carneiro (Apr 29 2020 at 04:02):

You can imagine that there is axiom sorry : \forall {A : Sort*}, A and whenever you use sorry it magically has whatever type it needs to have. It's not quite implemented like that but that's the idea

view this post on Zulip Reid Barton (Apr 29 2020 at 04:02):

sorry is yet another of those things nobody really understands. That's why you shouldn't use it in your proofs :upside_down:

view this post on Zulip Reid Barton (Apr 29 2020 at 04:02):

Like what even is a macro?

view this post on Zulip Mario Carneiro (Apr 29 2020 at 04:02):

a deeply mysterious thing

view this post on Zulip Steffan (Apr 29 2020 at 04:03):

that's why I don't like it :upside_down:
like, VSCode says a warning, yet it compiles...

Like what even is a macro?

Umm, I don't know, but in a github issue it said sorry was a macro.

view this post on Zulip Mario Carneiro (Apr 29 2020 at 04:03):

If you look at the expr type you will see that one of the options for an expr is a macro

view this post on Zulip Mario Carneiro (Apr 29 2020 at 04:04):

this is a kind of suspended computation, a promise that there is an expr here

view this post on Zulip Mario Carneiro (Apr 29 2020 at 04:04):

and some of them are lies like sorry

view this post on Zulip Adeeb K (Apr 29 2020 at 04:04):

so my proof is as follows: since (f (lift_one (m + 1) x)).val ≤ k and (f (lift_one (m + 1) y)).val ≤ k, by apply_relabel_lt we have relabel m k p (f (lift_one (m + 1) x)) = ⟨ (f (lift_one (m + 1) x)).val , (f (lift_one (m + 1) x)).val < m ⟩ and relabel m k p (f (lift_one (m + 1) y)) = ⟨ (f (lift_one (m + 1) x)).val , (f (lift_one (m + 1) y)).val < m ⟩. Since relabel m k p (f (lift_one (m + 1) x)) = relabel m k p (f (lift_one (m + 1) y))``. From this I would get something like (f (lift_one (m + 1) x)) = (f (lift_one (m + 1) y))```

view this post on Zulip Adeeb K (Apr 29 2020 at 04:05):

and then I could unpack using the injectivity of f and lift_one

view this post on Zulip Mario Carneiro (Apr 29 2020 at 04:06):

I suggest you modify the statement of apply_relabel_lt so that it says (relabel m k p x).1 = ... instead

view this post on Zulip Mario Carneiro (Apr 29 2020 at 04:06):

that way you don't have to worry about that proof component, that doesn't matter anyway

view this post on Zulip Adeeb K (Apr 29 2020 at 04:07):

okay, one second then

view this post on Zulip Adeeb K (Apr 29 2020 at 04:08):

alright, that's done.

view this post on Zulip Steffan (Apr 29 2020 at 04:10):

I proved that 1 = 2 with the help of sorry. Really.

theorem oet : 1 = 2 := sorry

theorem oett : 1 = 2 := begin
  apply oet,
end

view this post on Zulip Adeeb K (Apr 29 2020 at 04:21):

question

view this post on Zulip Adeeb K (Apr 29 2020 at 04:21):

suppose I have h : (f (lift_one (m + 1) x)).val = (f (lift_one (m + 1) y)).val

view this post on Zulip Adeeb K (Apr 29 2020 at 04:21):

how can I conclude that (f (lift_one (m + 1) x)) = (f (lift_one (m + 1) y)) knowing that the second part of the pair is that their values are bounded by m?

view this post on Zulip Reid Barton (Apr 29 2020 at 04:22):

Maybe Kevin wrote a lemma that can help you?

view this post on Zulip Adeeb K (Apr 29 2020 at 04:23):

oh, extensionality?

view this post on Zulip Adeeb K (Apr 29 2020 at 04:23):

wait, I thought that was the opposite

view this post on Zulip Adeeb K (Apr 29 2020 at 04:23):

...wait it was an iff

view this post on Zulip Adeeb K (Apr 29 2020 at 04:25):

I'm still getting an error

rewrite tactic failed, did not find instance of the pattern in the target expression

view this post on Zulip Adeeb K (Apr 29 2020 at 04:25):

when I used rw ext_iff at h,

view this post on Zulip Adeeb K (Apr 29 2020 at 04:25):

and h : (f (lift_one (m + 1) x)).val = (f (lift_one (m + 1) y)).val

view this post on Zulip Adeeb K (Apr 29 2020 at 04:34):

I'm not sure how to apply ext_iff in syntax here

view this post on Zulip Adeeb K (Apr 29 2020 at 04:34):

since rw ext_iff at h isn't working

view this post on Zulip Kenny Lau (Apr 29 2020 at 04:41):

-- subtype.ext : ∀ {α : Sort u_1} {p : α → Prop} {a1 a2 : {x // p x}}, a1 = a2 ↔ a1.val = a2.val
#check @subtype.ext

view this post on Zulip Adeeb K (Apr 29 2020 at 04:44):

I'm getting the same error using subtype.ext

view this post on Zulip Adeeb K (Apr 29 2020 at 04:44):

namely

rewrite tactic failed, did not find instance of the pattern in the target expression

view this post on Zulip Kenny Lau (Apr 29 2020 at 04:45):

you need to use \l

view this post on Zulip Kenny Lau (Apr 29 2020 at 04:45):

rw \l suubtype.ext

view this post on Zulip Kenny Lau (Apr 29 2020 at 04:45):

that's a lowercase L

view this post on Zulip Adeeb K (Apr 29 2020 at 04:52):

okay, that worked

view this post on Zulip Adeeb K (Apr 29 2020 at 05:13):

@Kenny Lau I'm not sure how to start the second part of the proof where

h :
  dite ((f (lift_one (m + 1) x)).val  k)
      (λ (H : (f (lift_one (m + 1) x)).val  k), (f (lift_one (m + 1) x)).val, _⟩)
      (λ (H : ¬(f (lift_one (m + 1) x)).val  k), (f (lift_one (m + 1) x)).val - 1, _⟩) =
    dite ((f (lift_one (m + 1) y)).val  k)
      (λ (H : (f (lift_one (m + 1) y)).val  k), (f (lift_one (m + 1) y)).val, _⟩)
      (λ (H : ¬(f (lift_one (m + 1) y)).val  k), (f (lift_one (m + 1) y)).val - 1, _⟩)

I remember that in the first part, you used this:

rw [dif_pos h1, dif_pos h2, subtype.mk_eq_mk] at h,

I'm wondering how I could adapt that for this case where (f (lift_one (m + 1) y)).val ≥ k.

view this post on Zulip Adeeb K (Apr 29 2020 at 05:15):

I'm not sure how to match this with dif_neg

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:29):

well you need to prove strict inequality

view this post on Zulip Adeeb K (Apr 29 2020 at 05:29):

I think I have that with miss right?

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:29):

you still need to prove it

view this post on Zulip Adeeb K (Apr 29 2020 at 05:29):

miss : ∀ j : finite_subset (m + 1), (f ∘ lift_one (m + 1)) j ≠ ⟨k, pf⟩

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:30):

because dite says "if p is true then ...; else ..."

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:30):

if you want to trigger the "else" clause then you need a proof of "not p"

view this post on Zulip Adeeb K (Apr 29 2020 at 05:31):

okay so then miss x is a proof that (f ∘ lift_one (m + 1)) x ≠ ⟨k, pf⟩ yes?

view this post on Zulip Adeeb K (Apr 29 2020 at 05:32):

so then subtype.ext (miss x) should be ((f ∘ lift_one (m + 1)) x).val ≠ ⟨k, pf⟩.val yes?

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:32):

sure

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:32):

now prove not (k \le _)

view this post on Zulip Adeeb K (Apr 29 2020 at 05:33):

I'm not sure what to do there

view this post on Zulip Adeeb K (Apr 29 2020 at 05:34):

do I break into cases using lt_or_eq_of_le?

view this post on Zulip Adeeb K (Apr 29 2020 at 05:35):

should I provide an MWE to show where I'm stuck?

view this post on Zulip Adeeb K (Apr 29 2020 at 05:35):

the problem I'm having is that I'm just not sure what syntax to use here..

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:36):

have hnk : \not k \le ...,

view this post on Zulip Kenny Lau (Apr 29 2020 at 05:36):

and after you prove it, rw dif_neg hnk

view this post on Zulip Adeeb K (Apr 29 2020 at 05:37):

one sec then

view this post on Zulip Adeeb K (Apr 29 2020 at 05:40):

wait, question about have.

view this post on Zulip Adeeb K (Apr 29 2020 at 05:41):

...what does it exactly do for me, and what would be the form to prove it?

view this post on Zulip Adeeb K (Apr 29 2020 at 05:51):

actually here's a related question

view this post on Zulip Adeeb K (Apr 29 2020 at 05:52):

how do I know that x ≠ y is~(x = y).

view this post on Zulip Bryan Gin-ge Chen (Apr 29 2020 at 05:54):

have lets you prove something that you want to use later and add it to the context. You may want to review some of the early chapters of TPiL, specifically this section.

view this post on Zulip Adeeb K (Apr 29 2020 at 05:55):

ah, so the basic pattern here is have <fact> from <proof>?

view this post on Zulip Bryan Gin-ge Chen (Apr 29 2020 at 05:57):

Not quite. have var_name : p, from <proof> or have var_name : p := <proof> where p : Prop.

view this post on Zulip Adeeb K (Apr 29 2020 at 05:58):

I see. One second

view this post on Zulip Bryan Gin-ge Chen (Apr 29 2020 at 05:58):

how do I know that x ≠ y is ~(x = y).

This is the definition of ne: https://github.com/leanprover-community/lean/blob/master/library/init/logic.lean#L97

view this post on Zulip Adeeb K (Apr 29 2020 at 06:03):

Then question: I have (f ∘ lift_one (m + 1)) x ≠ ⟨k, pf⟩. How do I conclude that ((f ∘ lift_one (m + 1)) x).1 ≠ ⟨k, pf⟩.1

{% endraw %}

Last updated: Apr 29 2020 at 06:04 UTC